##// END OF EJS Templates
patch: add fuzz config flag (issue4697)
Matt Mackall -
r25631:2748bf78 default
parent child Browse files
Show More
@@ -1,1792 +1,1797
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 .. container:: verbose.unix
31 .. container:: verbose.unix
32
32
33 On Unix, the following files are consulted:
33 On Unix, the following files are consulted:
34
34
35 - ``<repo>/.hg/hgrc`` (per-repository)
35 - ``<repo>/.hg/hgrc`` (per-repository)
36 - ``$HOME/.hgrc`` (per-user)
36 - ``$HOME/.hgrc`` (per-user)
37 - ``<install-root>/etc/mercurial/hgrc`` (per-installation)
37 - ``<install-root>/etc/mercurial/hgrc`` (per-installation)
38 - ``<install-root>/etc/mercurial/hgrc.d/*.rc`` (per-installation)
38 - ``<install-root>/etc/mercurial/hgrc.d/*.rc`` (per-installation)
39 - ``/etc/mercurial/hgrc`` (per-system)
39 - ``/etc/mercurial/hgrc`` (per-system)
40 - ``/etc/mercurial/hgrc.d/*.rc`` (per-system)
40 - ``/etc/mercurial/hgrc.d/*.rc`` (per-system)
41 - ``<internal>/default.d/*.rc`` (defaults)
41 - ``<internal>/default.d/*.rc`` (defaults)
42
42
43 .. container:: verbose.windows
43 .. container:: verbose.windows
44
44
45 On Windows, the following files are consulted:
45 On Windows, the following files are consulted:
46
46
47 - ``<repo>/.hg/hgrc`` (per-repository)
47 - ``<repo>/.hg/hgrc`` (per-repository)
48 - ``%USERPROFILE%\.hgrc`` (per-user)
48 - ``%USERPROFILE%\.hgrc`` (per-user)
49 - ``%USERPROFILE%\Mercurial.ini`` (per-user)
49 - ``%USERPROFILE%\Mercurial.ini`` (per-user)
50 - ``%HOME%\.hgrc`` (per-user)
50 - ``%HOME%\.hgrc`` (per-user)
51 - ``%HOME%\Mercurial.ini`` (per-user)
51 - ``%HOME%\Mercurial.ini`` (per-user)
52 - ``<install-dir>\Mercurial.ini`` (per-installation)
52 - ``<install-dir>\Mercurial.ini`` (per-installation)
53 - ``<install-dir>\hgrc.d\*.rc`` (per-installation)
53 - ``<install-dir>\hgrc.d\*.rc`` (per-installation)
54 - ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial`` (per-installation)
54 - ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial`` (per-installation)
55 - ``<internal>/default.d/*.rc`` (defaults)
55 - ``<internal>/default.d/*.rc`` (defaults)
56
56
57 .. note::
57 .. note::
58
58
59 The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
59 The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
60 is used when running 32-bit Python on 64-bit Windows.
60 is used when running 32-bit Python on 64-bit Windows.
61
61
62 .. container:: verbose.plan9
62 .. container:: verbose.plan9
63
63
64 On Plan9, the following files are consulted:
64 On Plan9, the following files are consulted:
65
65
66 - ``<repo>/.hg/hgrc`` (per-repository)
66 - ``<repo>/.hg/hgrc`` (per-repository)
67 - ``$home/lib/hgrc`` (per-user)
67 - ``$home/lib/hgrc`` (per-user)
68 - ``<install-root>/lib/mercurial/hgrc`` (per-installation)
68 - ``<install-root>/lib/mercurial/hgrc`` (per-installation)
69 - ``<install-root>/lib/mercurial/hgrc.d/*.rc`` (per-installation)
69 - ``<install-root>/lib/mercurial/hgrc.d/*.rc`` (per-installation)
70 - ``/lib/mercurial/hgrc`` (per-system)
70 - ``/lib/mercurial/hgrc`` (per-system)
71 - ``/lib/mercurial/hgrc.d/*.rc`` (per-system)
71 - ``/lib/mercurial/hgrc.d/*.rc`` (per-system)
72 - ``<internal>/default.d/*.rc`` (defaults)
72 - ``<internal>/default.d/*.rc`` (defaults)
73
73
74 Per-repository configuration options only apply in a
74 Per-repository configuration options only apply in a
75 particular repository. This file is not version-controlled, and
75 particular repository. This file is not version-controlled, and
76 will not get transferred during a "clone" operation. Options in
76 will not get transferred during a "clone" operation. Options in
77 this file override options in all other configuration files. On
77 this file override options in all other configuration files. On
78 Plan 9 and Unix, most of this file will be ignored if it doesn't
78 Plan 9 and Unix, most of this file will be ignored if it doesn't
79 belong to a trusted user or to a trusted group. See the documentation
79 belong to a trusted user or to a trusted group. See the documentation
80 for the ``[trusted]`` section below for more details.
80 for the ``[trusted]`` section below for more details.
81
81
82 Per-user configuration file(s) are for the user running Mercurial. On
82 Per-user configuration file(s) are for the user running Mercurial. On
83 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
83 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
84 files apply to all Mercurial commands executed by this user in any
84 files apply to all Mercurial commands executed by this user in any
85 directory. Options in these files override per-system and per-installation
85 directory. Options in these files override per-system and per-installation
86 options.
86 options.
87
87
88 Per-installation configuration files are searched for in the
88 Per-installation configuration files are searched for in the
89 directory where Mercurial is installed. ``<install-root>`` is the
89 directory where Mercurial is installed. ``<install-root>`` is the
90 parent directory of the **hg** executable (or symlink) being run. For
90 parent directory of the **hg** executable (or symlink) being run. For
91 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
91 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
92 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
92 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
93 to all Mercurial commands executed by any user in any directory.
93 to all Mercurial commands executed by any user in any directory.
94
94
95 Per-installation configuration files are for the system on
95 Per-installation configuration files are for the system on
96 which Mercurial is running. Options in these files apply to all
96 which Mercurial is running. Options in these files apply to all
97 Mercurial commands executed by any user in any directory. Registry
97 Mercurial commands executed by any user in any directory. Registry
98 keys contain PATH-like strings, every part of which must reference
98 keys contain PATH-like strings, every part of which must reference
99 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
99 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
100 be read. Mercurial checks each of these locations in the specified
100 be read. Mercurial checks each of these locations in the specified
101 order until one or more configuration files are detected.
101 order until one or more configuration files are detected.
102
102
103 Per-system configuration files are for the system on which Mercurial
103 Per-system configuration files are for the system on which Mercurial
104 is running. Options in these files apply to all Mercurial commands
104 is running. Options in these files apply to all Mercurial commands
105 executed by any user in any directory. Options in these files
105 executed by any user in any directory. Options in these files
106 override per-installation options.
106 override per-installation options.
107
107
108 Mercurial comes with some default configuration. The default configuration
108 Mercurial comes with some default configuration. The default configuration
109 files are installed with Mercurial and will be overwritten on upgrades. Default
109 files are installed with Mercurial and will be overwritten on upgrades. Default
110 configuration files should never be edited by users or administrators but can
110 configuration files should never be edited by users or administrators but can
111 be overridden in other configuration files. So far the directory only contains
111 be overridden in other configuration files. So far the directory only contains
112 merge tool configuration but packagers can also put other default configuration
112 merge tool configuration but packagers can also put other default configuration
113 there.
113 there.
114
114
115 Syntax
115 Syntax
116 ======
116 ======
117
117
118 A configuration file consists of sections, led by a ``[section]`` header
118 A configuration file consists of sections, led by a ``[section]`` header
119 and followed by ``name = value`` entries (sometimes called
119 and followed by ``name = value`` entries (sometimes called
120 ``configuration keys``)::
120 ``configuration keys``)::
121
121
122 [spam]
122 [spam]
123 eggs=ham
123 eggs=ham
124 green=
124 green=
125 eggs
125 eggs
126
126
127 Each line contains one entry. If the lines that follow are indented,
127 Each line contains one entry. If the lines that follow are indented,
128 they are treated as continuations of that entry. Leading whitespace is
128 they are treated as continuations of that entry. Leading whitespace is
129 removed from values. Empty lines are skipped. Lines beginning with
129 removed from values. Empty lines are skipped. Lines beginning with
130 ``#`` or ``;`` are ignored and may be used to provide comments.
130 ``#`` or ``;`` are ignored and may be used to provide comments.
131
131
132 Configuration keys can be set multiple times, in which case Mercurial
132 Configuration keys can be set multiple times, in which case Mercurial
133 will use the value that was configured last. As an example::
133 will use the value that was configured last. As an example::
134
134
135 [spam]
135 [spam]
136 eggs=large
136 eggs=large
137 ham=serrano
137 ham=serrano
138 eggs=small
138 eggs=small
139
139
140 This would set the configuration key named ``eggs`` to ``small``.
140 This would set the configuration key named ``eggs`` to ``small``.
141
141
142 It is also possible to define a section multiple times. A section can
142 It is also possible to define a section multiple times. A section can
143 be redefined on the same and/or on different configuration files. For
143 be redefined on the same and/or on different configuration files. For
144 example::
144 example::
145
145
146 [foo]
146 [foo]
147 eggs=large
147 eggs=large
148 ham=serrano
148 ham=serrano
149 eggs=small
149 eggs=small
150
150
151 [bar]
151 [bar]
152 eggs=ham
152 eggs=ham
153 green=
153 green=
154 eggs
154 eggs
155
155
156 [foo]
156 [foo]
157 ham=prosciutto
157 ham=prosciutto
158 eggs=medium
158 eggs=medium
159 bread=toasted
159 bread=toasted
160
160
161 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
161 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
162 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
162 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
163 respectively. As you can see there only thing that matters is the last
163 respectively. As you can see there only thing that matters is the last
164 value that was set for each of the configuration keys.
164 value that was set for each of the configuration keys.
165
165
166 If a configuration key is set multiple times in different
166 If a configuration key is set multiple times in different
167 configuration files the final value will depend on the order in which
167 configuration files the final value will depend on the order in which
168 the different configuration files are read, with settings from earlier
168 the different configuration files are read, with settings from earlier
169 paths overriding later ones as described on the ``Files`` section
169 paths overriding later ones as described on the ``Files`` section
170 above.
170 above.
171
171
172 A line of the form ``%include file`` will include ``file`` into the
172 A line of the form ``%include file`` will include ``file`` into the
173 current configuration file. The inclusion is recursive, which means
173 current configuration file. The inclusion is recursive, which means
174 that included files can include other files. Filenames are relative to
174 that included files can include other files. Filenames are relative to
175 the configuration file in which the ``%include`` directive is found.
175 the configuration file in which the ``%include`` directive is found.
176 Environment variables and ``~user`` constructs are expanded in
176 Environment variables and ``~user`` constructs are expanded in
177 ``file``. This lets you do something like::
177 ``file``. This lets you do something like::
178
178
179 %include ~/.hgrc.d/$HOST.rc
179 %include ~/.hgrc.d/$HOST.rc
180
180
181 to include a different configuration file on each computer you use.
181 to include a different configuration file on each computer you use.
182
182
183 A line with ``%unset name`` will remove ``name`` from the current
183 A line with ``%unset name`` will remove ``name`` from the current
184 section, if it has been set previously.
184 section, if it has been set previously.
185
185
186 The values are either free-form text strings, lists of text strings,
186 The values are either free-form text strings, lists of text strings,
187 or Boolean values. Boolean values can be set to true using any of "1",
187 or Boolean values. Boolean values can be set to true using any of "1",
188 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
188 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
189 (all case insensitive).
189 (all case insensitive).
190
190
191 List values are separated by whitespace or comma, except when values are
191 List values are separated by whitespace or comma, except when values are
192 placed in double quotation marks::
192 placed in double quotation marks::
193
193
194 allow_read = "John Doe, PhD", brian, betty
194 allow_read = "John Doe, PhD", brian, betty
195
195
196 Quotation marks can be escaped by prefixing them with a backslash. Only
196 Quotation marks can be escaped by prefixing them with a backslash. Only
197 quotation marks at the beginning of a word is counted as a quotation
197 quotation marks at the beginning of a word is counted as a quotation
198 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
198 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
199
199
200 Sections
200 Sections
201 ========
201 ========
202
202
203 This section describes the different sections that may appear in a
203 This section describes the different sections that may appear in a
204 Mercurial configuration file, the purpose of each section, its possible
204 Mercurial configuration file, the purpose of each section, its possible
205 keys, and their possible values.
205 keys, and their possible values.
206
206
207 ``alias``
207 ``alias``
208 ---------
208 ---------
209
209
210 Defines command aliases.
210 Defines command aliases.
211 Aliases allow you to define your own commands in terms of other
211 Aliases allow you to define your own commands in terms of other
212 commands (or aliases), optionally including arguments. Positional
212 commands (or aliases), optionally including arguments. Positional
213 arguments in the form of ``$1``, ``$2``, etc in the alias definition
213 arguments in the form of ``$1``, ``$2``, etc in the alias definition
214 are expanded by Mercurial before execution. Positional arguments not
214 are expanded by Mercurial before execution. Positional arguments not
215 already used by ``$N`` in the definition are put at the end of the
215 already used by ``$N`` in the definition are put at the end of the
216 command to be executed.
216 command to be executed.
217
217
218 Alias definitions consist of lines of the form::
218 Alias definitions consist of lines of the form::
219
219
220 <alias> = <command> [<argument>]...
220 <alias> = <command> [<argument>]...
221
221
222 For example, this definition::
222 For example, this definition::
223
223
224 latest = log --limit 5
224 latest = log --limit 5
225
225
226 creates a new command ``latest`` that shows only the five most recent
226 creates a new command ``latest`` that shows only the five most recent
227 changesets. You can define subsequent aliases using earlier ones::
227 changesets. You can define subsequent aliases using earlier ones::
228
228
229 stable5 = latest -b stable
229 stable5 = latest -b stable
230
230
231 .. note::
231 .. note::
232
232
233 It is possible to create aliases with the same names as
233 It is possible to create aliases with the same names as
234 existing commands, which will then override the original
234 existing commands, which will then override the original
235 definitions. This is almost always a bad idea!
235 definitions. This is almost always a bad idea!
236
236
237 An alias can start with an exclamation point (``!``) to make it a
237 An alias can start with an exclamation point (``!``) to make it a
238 shell alias. A shell alias is executed with the shell and will let you
238 shell alias. A shell alias is executed with the shell and will let you
239 run arbitrary commands. As an example, ::
239 run arbitrary commands. As an example, ::
240
240
241 echo = !echo $@
241 echo = !echo $@
242
242
243 will let you do ``hg echo foo`` to have ``foo`` printed in your
243 will let you do ``hg echo foo`` to have ``foo`` printed in your
244 terminal. A better example might be::
244 terminal. A better example might be::
245
245
246 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
246 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
247
247
248 which will make ``hg purge`` delete all unknown files in the
248 which will make ``hg purge`` delete all unknown files in the
249 repository in the same manner as the purge extension.
249 repository in the same manner as the purge extension.
250
250
251 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
251 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
252 expand to the command arguments. Unmatched arguments are
252 expand to the command arguments. Unmatched arguments are
253 removed. ``$0`` expands to the alias name and ``$@`` expands to all
253 removed. ``$0`` expands to the alias name and ``$@`` expands to all
254 arguments separated by a space. ``"$@"`` (with quotes) expands to all
254 arguments separated by a space. ``"$@"`` (with quotes) expands to all
255 arguments quoted individually and separated by a space. These expansions
255 arguments quoted individually and separated by a space. These expansions
256 happen before the command is passed to the shell.
256 happen before the command is passed to the shell.
257
257
258 Shell aliases are executed in an environment where ``$HG`` expands to
258 Shell aliases are executed in an environment where ``$HG`` expands to
259 the path of the Mercurial that was used to execute the alias. This is
259 the path of the Mercurial that was used to execute the alias. This is
260 useful when you want to call further Mercurial commands in a shell
260 useful when you want to call further Mercurial commands in a shell
261 alias, as was done above for the purge alias. In addition,
261 alias, as was done above for the purge alias. In addition,
262 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
262 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
263 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
263 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
264
264
265 .. note::
265 .. note::
266
266
267 Some global configuration options such as ``-R`` are
267 Some global configuration options such as ``-R`` are
268 processed before shell aliases and will thus not be passed to
268 processed before shell aliases and will thus not be passed to
269 aliases.
269 aliases.
270
270
271
271
272 ``annotate``
272 ``annotate``
273 ------------
273 ------------
274
274
275 Settings used when displaying file annotations. All values are
275 Settings used when displaying file annotations. All values are
276 Booleans and default to False. See ``diff`` section for related
276 Booleans and default to False. See ``diff`` section for related
277 options for the diff command.
277 options for the diff command.
278
278
279 ``ignorews``
279 ``ignorews``
280 Ignore white space when comparing lines.
280 Ignore white space when comparing lines.
281
281
282 ``ignorewsamount``
282 ``ignorewsamount``
283 Ignore changes in the amount of white space.
283 Ignore changes in the amount of white space.
284
284
285 ``ignoreblanklines``
285 ``ignoreblanklines``
286 Ignore changes whose lines are all blank.
286 Ignore changes whose lines are all blank.
287
287
288
288
289 ``auth``
289 ``auth``
290 --------
290 --------
291
291
292 Authentication credentials for HTTP authentication. This section
292 Authentication credentials for HTTP authentication. This section
293 allows you to store usernames and passwords for use when logging
293 allows you to store usernames and passwords for use when logging
294 *into* HTTP servers. See the ``[web]`` configuration section if
294 *into* HTTP servers. See the ``[web]`` configuration section if
295 you want to configure *who* can login to your HTTP server.
295 you want to configure *who* can login to your HTTP server.
296
296
297 Each line has the following format::
297 Each line has the following format::
298
298
299 <name>.<argument> = <value>
299 <name>.<argument> = <value>
300
300
301 where ``<name>`` is used to group arguments into authentication
301 where ``<name>`` is used to group arguments into authentication
302 entries. Example::
302 entries. Example::
303
303
304 foo.prefix = hg.intevation.org/mercurial
304 foo.prefix = hg.intevation.org/mercurial
305 foo.username = foo
305 foo.username = foo
306 foo.password = bar
306 foo.password = bar
307 foo.schemes = http https
307 foo.schemes = http https
308
308
309 bar.prefix = secure.example.org
309 bar.prefix = secure.example.org
310 bar.key = path/to/file.key
310 bar.key = path/to/file.key
311 bar.cert = path/to/file.cert
311 bar.cert = path/to/file.cert
312 bar.schemes = https
312 bar.schemes = https
313
313
314 Supported arguments:
314 Supported arguments:
315
315
316 ``prefix``
316 ``prefix``
317 Either ``*`` or a URI prefix with or without the scheme part.
317 Either ``*`` or a URI prefix with or without the scheme part.
318 The authentication entry with the longest matching prefix is used
318 The authentication entry with the longest matching prefix is used
319 (where ``*`` matches everything and counts as a match of length
319 (where ``*`` matches everything and counts as a match of length
320 1). If the prefix doesn't include a scheme, the match is performed
320 1). If the prefix doesn't include a scheme, the match is performed
321 against the URI with its scheme stripped as well, and the schemes
321 against the URI with its scheme stripped as well, and the schemes
322 argument, q.v., is then subsequently consulted.
322 argument, q.v., is then subsequently consulted.
323
323
324 ``username``
324 ``username``
325 Optional. Username to authenticate with. If not given, and the
325 Optional. Username to authenticate with. If not given, and the
326 remote site requires basic or digest authentication, the user will
326 remote site requires basic or digest authentication, the user will
327 be prompted for it. Environment variables are expanded in the
327 be prompted for it. Environment variables are expanded in the
328 username letting you do ``foo.username = $USER``. If the URI
328 username letting you do ``foo.username = $USER``. If the URI
329 includes a username, only ``[auth]`` entries with a matching
329 includes a username, only ``[auth]`` entries with a matching
330 username or without a username will be considered.
330 username or without a username will be considered.
331
331
332 ``password``
332 ``password``
333 Optional. Password to authenticate with. If not given, and the
333 Optional. Password to authenticate with. If not given, and the
334 remote site requires basic or digest authentication, the user
334 remote site requires basic or digest authentication, the user
335 will be prompted for it.
335 will be prompted for it.
336
336
337 ``key``
337 ``key``
338 Optional. PEM encoded client certificate key file. Environment
338 Optional. PEM encoded client certificate key file. Environment
339 variables are expanded in the filename.
339 variables are expanded in the filename.
340
340
341 ``cert``
341 ``cert``
342 Optional. PEM encoded client certificate chain file. Environment
342 Optional. PEM encoded client certificate chain file. Environment
343 variables are expanded in the filename.
343 variables are expanded in the filename.
344
344
345 ``schemes``
345 ``schemes``
346 Optional. Space separated list of URI schemes to use this
346 Optional. Space separated list of URI schemes to use this
347 authentication entry with. Only used if the prefix doesn't include
347 authentication entry with. Only used if the prefix doesn't include
348 a scheme. Supported schemes are http and https. They will match
348 a scheme. Supported schemes are http and https. They will match
349 static-http and static-https respectively, as well.
349 static-http and static-https respectively, as well.
350 Default: https.
350 Default: https.
351
351
352 If no suitable authentication entry is found, the user is prompted
352 If no suitable authentication entry is found, the user is prompted
353 for credentials as usual if required by the remote.
353 for credentials as usual if required by the remote.
354
354
355
355
356 ``committemplate``
356 ``committemplate``
357 ------------------
357 ------------------
358
358
359 ``changeset`` configuration in this section is used as the template to
359 ``changeset`` configuration in this section is used as the template to
360 customize the text shown in the editor when committing.
360 customize the text shown in the editor when committing.
361
361
362 In addition to pre-defined template keywords, commit log specific one
362 In addition to pre-defined template keywords, commit log specific one
363 below can be used for customization:
363 below can be used for customization:
364
364
365 ``extramsg``
365 ``extramsg``
366 String: Extra message (typically 'Leave message empty to abort
366 String: Extra message (typically 'Leave message empty to abort
367 commit.'). This may be changed by some commands or extensions.
367 commit.'). This may be changed by some commands or extensions.
368
368
369 For example, the template configuration below shows as same text as
369 For example, the template configuration below shows as same text as
370 one shown by default::
370 one shown by default::
371
371
372 [committemplate]
372 [committemplate]
373 changeset = {desc}\n\n
373 changeset = {desc}\n\n
374 HG: Enter commit message. Lines beginning with 'HG:' are removed.
374 HG: Enter commit message. Lines beginning with 'HG:' are removed.
375 HG: {extramsg}
375 HG: {extramsg}
376 HG: --
376 HG: --
377 HG: user: {author}\n{ifeq(p2rev, "-1", "",
377 HG: user: {author}\n{ifeq(p2rev, "-1", "",
378 "HG: branch merge\n")
378 "HG: branch merge\n")
379 }HG: branch '{branch}'\n{if(activebookmark,
379 }HG: branch '{branch}'\n{if(activebookmark,
380 "HG: bookmark '{activebookmark}'\n") }{subrepos %
380 "HG: bookmark '{activebookmark}'\n") }{subrepos %
381 "HG: subrepo {subrepo}\n" }{file_adds %
381 "HG: subrepo {subrepo}\n" }{file_adds %
382 "HG: added {file}\n" }{file_mods %
382 "HG: added {file}\n" }{file_mods %
383 "HG: changed {file}\n" }{file_dels %
383 "HG: changed {file}\n" }{file_dels %
384 "HG: removed {file}\n" }{if(files, "",
384 "HG: removed {file}\n" }{if(files, "",
385 "HG: no files changed\n")}
385 "HG: no files changed\n")}
386
386
387 .. note::
387 .. note::
388
388
389 For some problematic encodings (see :hg:`help win32mbcs` for
389 For some problematic encodings (see :hg:`help win32mbcs` for
390 detail), this customization should be configured carefully, to
390 detail), this customization should be configured carefully, to
391 avoid showing broken characters.
391 avoid showing broken characters.
392
392
393 For example, if multibyte character ending with backslash (0x5c) is
393 For example, if multibyte character ending with backslash (0x5c) is
394 followed by ASCII character 'n' in the customized template,
394 followed by ASCII character 'n' in the customized template,
395 sequence of backslash and 'n' is treated as line-feed unexpectedly
395 sequence of backslash and 'n' is treated as line-feed unexpectedly
396 (and multibyte character is broken, too).
396 (and multibyte character is broken, too).
397
397
398 Customized template is used for commands below (``--edit`` may be
398 Customized template is used for commands below (``--edit`` may be
399 required):
399 required):
400
400
401 - :hg:`backout`
401 - :hg:`backout`
402 - :hg:`commit`
402 - :hg:`commit`
403 - :hg:`fetch` (for merge commit only)
403 - :hg:`fetch` (for merge commit only)
404 - :hg:`graft`
404 - :hg:`graft`
405 - :hg:`histedit`
405 - :hg:`histedit`
406 - :hg:`import`
406 - :hg:`import`
407 - :hg:`qfold`, :hg:`qnew` and :hg:`qrefresh`
407 - :hg:`qfold`, :hg:`qnew` and :hg:`qrefresh`
408 - :hg:`rebase`
408 - :hg:`rebase`
409 - :hg:`shelve`
409 - :hg:`shelve`
410 - :hg:`sign`
410 - :hg:`sign`
411 - :hg:`tag`
411 - :hg:`tag`
412 - :hg:`transplant`
412 - :hg:`transplant`
413
413
414 Configuring items below instead of ``changeset`` allows showing
414 Configuring items below instead of ``changeset`` allows showing
415 customized message only for specific actions, or showing different
415 customized message only for specific actions, or showing different
416 messages for each action.
416 messages for each action.
417
417
418 - ``changeset.backout`` for :hg:`backout`
418 - ``changeset.backout`` for :hg:`backout`
419 - ``changeset.commit.amend.merge`` for :hg:`commit --amend` on merges
419 - ``changeset.commit.amend.merge`` for :hg:`commit --amend` on merges
420 - ``changeset.commit.amend.normal`` for :hg:`commit --amend` on other
420 - ``changeset.commit.amend.normal`` for :hg:`commit --amend` on other
421 - ``changeset.commit.normal.merge`` for :hg:`commit` on merges
421 - ``changeset.commit.normal.merge`` for :hg:`commit` on merges
422 - ``changeset.commit.normal.normal`` for :hg:`commit` on other
422 - ``changeset.commit.normal.normal`` for :hg:`commit` on other
423 - ``changeset.fetch`` for :hg:`fetch` (impling merge commit)
423 - ``changeset.fetch`` for :hg:`fetch` (impling merge commit)
424 - ``changeset.gpg.sign`` for :hg:`sign`
424 - ``changeset.gpg.sign`` for :hg:`sign`
425 - ``changeset.graft`` for :hg:`graft`
425 - ``changeset.graft`` for :hg:`graft`
426 - ``changeset.histedit.edit`` for ``edit`` of :hg:`histedit`
426 - ``changeset.histedit.edit`` for ``edit`` of :hg:`histedit`
427 - ``changeset.histedit.fold`` for ``fold`` of :hg:`histedit`
427 - ``changeset.histedit.fold`` for ``fold`` of :hg:`histedit`
428 - ``changeset.histedit.mess`` for ``mess`` of :hg:`histedit`
428 - ``changeset.histedit.mess`` for ``mess`` of :hg:`histedit`
429 - ``changeset.histedit.pick`` for ``pick`` of :hg:`histedit`
429 - ``changeset.histedit.pick`` for ``pick`` of :hg:`histedit`
430 - ``changeset.import.bypass`` for :hg:`import --bypass`
430 - ``changeset.import.bypass`` for :hg:`import --bypass`
431 - ``changeset.import.normal.merge`` for :hg:`import` on merges
431 - ``changeset.import.normal.merge`` for :hg:`import` on merges
432 - ``changeset.import.normal.normal`` for :hg:`import` on other
432 - ``changeset.import.normal.normal`` for :hg:`import` on other
433 - ``changeset.mq.qnew`` for :hg:`qnew`
433 - ``changeset.mq.qnew`` for :hg:`qnew`
434 - ``changeset.mq.qfold`` for :hg:`qfold`
434 - ``changeset.mq.qfold`` for :hg:`qfold`
435 - ``changeset.mq.qrefresh`` for :hg:`qrefresh`
435 - ``changeset.mq.qrefresh`` for :hg:`qrefresh`
436 - ``changeset.rebase.collapse`` for :hg:`rebase --collapse`
436 - ``changeset.rebase.collapse`` for :hg:`rebase --collapse`
437 - ``changeset.rebase.merge`` for :hg:`rebase` on merges
437 - ``changeset.rebase.merge`` for :hg:`rebase` on merges
438 - ``changeset.rebase.normal`` for :hg:`rebase` on other
438 - ``changeset.rebase.normal`` for :hg:`rebase` on other
439 - ``changeset.shelve.shelve`` for :hg:`shelve`
439 - ``changeset.shelve.shelve`` for :hg:`shelve`
440 - ``changeset.tag.add`` for :hg:`tag` without ``--remove``
440 - ``changeset.tag.add`` for :hg:`tag` without ``--remove``
441 - ``changeset.tag.remove`` for :hg:`tag --remove`
441 - ``changeset.tag.remove`` for :hg:`tag --remove`
442 - ``changeset.transplant.merge`` for :hg:`transplant` on merges
442 - ``changeset.transplant.merge`` for :hg:`transplant` on merges
443 - ``changeset.transplant.normal`` for :hg:`transplant` on other
443 - ``changeset.transplant.normal`` for :hg:`transplant` on other
444
444
445 These dot-separated lists of names are treated as hierarchical ones.
445 These dot-separated lists of names are treated as hierarchical ones.
446 For example, ``changeset.tag.remove`` customizes the commit message
446 For example, ``changeset.tag.remove`` customizes the commit message
447 only for :hg:`tag --remove`, but ``changeset.tag`` customizes the
447 only for :hg:`tag --remove`, but ``changeset.tag`` customizes the
448 commit message for :hg:`tag` regardless of ``--remove`` option.
448 commit message for :hg:`tag` regardless of ``--remove`` option.
449
449
450 At the external editor invocation for committing, corresponding
450 At the external editor invocation for committing, corresponding
451 dot-separated list of names without ``changeset.`` prefix
451 dot-separated list of names without ``changeset.`` prefix
452 (e.g. ``commit.normal.normal``) is in ``HGEDITFORM`` environment variable.
452 (e.g. ``commit.normal.normal``) is in ``HGEDITFORM`` environment variable.
453
453
454 In this section, items other than ``changeset`` can be referred from
454 In this section, items other than ``changeset`` can be referred from
455 others. For example, the configuration to list committed files up
455 others. For example, the configuration to list committed files up
456 below can be referred as ``{listupfiles}``::
456 below can be referred as ``{listupfiles}``::
457
457
458 [committemplate]
458 [committemplate]
459 listupfiles = {file_adds %
459 listupfiles = {file_adds %
460 "HG: added {file}\n" }{file_mods %
460 "HG: added {file}\n" }{file_mods %
461 "HG: changed {file}\n" }{file_dels %
461 "HG: changed {file}\n" }{file_dels %
462 "HG: removed {file}\n" }{if(files, "",
462 "HG: removed {file}\n" }{if(files, "",
463 "HG: no files changed\n")}
463 "HG: no files changed\n")}
464
464
465 ``decode/encode``
465 ``decode/encode``
466 -----------------
466 -----------------
467
467
468 Filters for transforming files on checkout/checkin. This would
468 Filters for transforming files on checkout/checkin. This would
469 typically be used for newline processing or other
469 typically be used for newline processing or other
470 localization/canonicalization of files.
470 localization/canonicalization of files.
471
471
472 Filters consist of a filter pattern followed by a filter command.
472 Filters consist of a filter pattern followed by a filter command.
473 Filter patterns are globs by default, rooted at the repository root.
473 Filter patterns are globs by default, rooted at the repository root.
474 For example, to match any file ending in ``.txt`` in the root
474 For example, to match any file ending in ``.txt`` in the root
475 directory only, use the pattern ``*.txt``. To match any file ending
475 directory only, use the pattern ``*.txt``. To match any file ending
476 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
476 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
477 For each file only the first matching filter applies.
477 For each file only the first matching filter applies.
478
478
479 The filter command can start with a specifier, either ``pipe:`` or
479 The filter command can start with a specifier, either ``pipe:`` or
480 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
480 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
481
481
482 A ``pipe:`` command must accept data on stdin and return the transformed
482 A ``pipe:`` command must accept data on stdin and return the transformed
483 data on stdout.
483 data on stdout.
484
484
485 Pipe example::
485 Pipe example::
486
486
487 [encode]
487 [encode]
488 # uncompress gzip files on checkin to improve delta compression
488 # uncompress gzip files on checkin to improve delta compression
489 # note: not necessarily a good idea, just an example
489 # note: not necessarily a good idea, just an example
490 *.gz = pipe: gunzip
490 *.gz = pipe: gunzip
491
491
492 [decode]
492 [decode]
493 # recompress gzip files when writing them to the working dir (we
493 # recompress gzip files when writing them to the working dir (we
494 # can safely omit "pipe:", because it's the default)
494 # can safely omit "pipe:", because it's the default)
495 *.gz = gzip
495 *.gz = gzip
496
496
497 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
497 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
498 with the name of a temporary file that contains the data to be
498 with the name of a temporary file that contains the data to be
499 filtered by the command. The string ``OUTFILE`` is replaced with the name
499 filtered by the command. The string ``OUTFILE`` is replaced with the name
500 of an empty temporary file, where the filtered data must be written by
500 of an empty temporary file, where the filtered data must be written by
501 the command.
501 the command.
502
502
503 .. note::
503 .. note::
504
504
505 The tempfile mechanism is recommended for Windows systems,
505 The tempfile mechanism is recommended for Windows systems,
506 where the standard shell I/O redirection operators often have
506 where the standard shell I/O redirection operators often have
507 strange effects and may corrupt the contents of your files.
507 strange effects and may corrupt the contents of your files.
508
508
509 This filter mechanism is used internally by the ``eol`` extension to
509 This filter mechanism is used internally by the ``eol`` extension to
510 translate line ending characters between Windows (CRLF) and Unix (LF)
510 translate line ending characters between Windows (CRLF) and Unix (LF)
511 format. We suggest you use the ``eol`` extension for convenience.
511 format. We suggest you use the ``eol`` extension for convenience.
512
512
513
513
514 ``defaults``
514 ``defaults``
515 ------------
515 ------------
516
516
517 (defaults are deprecated. Don't use them. Use aliases instead)
517 (defaults are deprecated. Don't use them. Use aliases instead)
518
518
519 Use the ``[defaults]`` section to define command defaults, i.e. the
519 Use the ``[defaults]`` section to define command defaults, i.e. the
520 default options/arguments to pass to the specified commands.
520 default options/arguments to pass to the specified commands.
521
521
522 The following example makes :hg:`log` run in verbose mode, and
522 The following example makes :hg:`log` run in verbose mode, and
523 :hg:`status` show only the modified files, by default::
523 :hg:`status` show only the modified files, by default::
524
524
525 [defaults]
525 [defaults]
526 log = -v
526 log = -v
527 status = -m
527 status = -m
528
528
529 The actual commands, instead of their aliases, must be used when
529 The actual commands, instead of their aliases, must be used when
530 defining command defaults. The command defaults will also be applied
530 defining command defaults. The command defaults will also be applied
531 to the aliases of the commands defined.
531 to the aliases of the commands defined.
532
532
533
533
534 ``diff``
534 ``diff``
535 --------
535 --------
536
536
537 Settings used when displaying diffs. Everything except for ``unified``
537 Settings used when displaying diffs. Everything except for ``unified``
538 is a Boolean and defaults to False. See ``annotate`` section for
538 is a Boolean and defaults to False. See ``annotate`` section for
539 related options for the annotate command.
539 related options for the annotate command.
540
540
541 ``git``
541 ``git``
542 Use git extended diff format.
542 Use git extended diff format.
543
543
544 ``nobinary``
544 ``nobinary``
545 Omit git binary patches.
545 Omit git binary patches.
546
546
547 ``nodates``
547 ``nodates``
548 Don't include dates in diff headers.
548 Don't include dates in diff headers.
549
549
550 ``noprefix``
550 ``noprefix``
551 Omit 'a/' and 'b/' prefixes from filenames. Ignored in plain mode.
551 Omit 'a/' and 'b/' prefixes from filenames. Ignored in plain mode.
552
552
553 ``showfunc``
553 ``showfunc``
554 Show which function each change is in.
554 Show which function each change is in.
555
555
556 ``ignorews``
556 ``ignorews``
557 Ignore white space when comparing lines.
557 Ignore white space when comparing lines.
558
558
559 ``ignorewsamount``
559 ``ignorewsamount``
560 Ignore changes in the amount of white space.
560 Ignore changes in the amount of white space.
561
561
562 ``ignoreblanklines``
562 ``ignoreblanklines``
563 Ignore changes whose lines are all blank.
563 Ignore changes whose lines are all blank.
564
564
565 ``unified``
565 ``unified``
566 Number of lines of context to show.
566 Number of lines of context to show.
567
567
568 ``email``
568 ``email``
569 ---------
569 ---------
570
570
571 Settings for extensions that send email messages.
571 Settings for extensions that send email messages.
572
572
573 ``from``
573 ``from``
574 Optional. Email address to use in "From" header and SMTP envelope
574 Optional. Email address to use in "From" header and SMTP envelope
575 of outgoing messages.
575 of outgoing messages.
576
576
577 ``to``
577 ``to``
578 Optional. Comma-separated list of recipients' email addresses.
578 Optional. Comma-separated list of recipients' email addresses.
579
579
580 ``cc``
580 ``cc``
581 Optional. Comma-separated list of carbon copy recipients'
581 Optional. Comma-separated list of carbon copy recipients'
582 email addresses.
582 email addresses.
583
583
584 ``bcc``
584 ``bcc``
585 Optional. Comma-separated list of blind carbon copy recipients'
585 Optional. Comma-separated list of blind carbon copy recipients'
586 email addresses.
586 email addresses.
587
587
588 ``method``
588 ``method``
589 Optional. Method to use to send email messages. If value is ``smtp``
589 Optional. Method to use to send email messages. If value is ``smtp``
590 (default), use SMTP (see the ``[smtp]`` section for configuration).
590 (default), use SMTP (see the ``[smtp]`` section for configuration).
591 Otherwise, use as name of program to run that acts like sendmail
591 Otherwise, use as name of program to run that acts like sendmail
592 (takes ``-f`` option for sender, list of recipients on command line,
592 (takes ``-f`` option for sender, list of recipients on command line,
593 message on stdin). Normally, setting this to ``sendmail`` or
593 message on stdin). Normally, setting this to ``sendmail`` or
594 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
594 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
595
595
596 ``charsets``
596 ``charsets``
597 Optional. Comma-separated list of character sets considered
597 Optional. Comma-separated list of character sets considered
598 convenient for recipients. Addresses, headers, and parts not
598 convenient for recipients. Addresses, headers, and parts not
599 containing patches of outgoing messages will be encoded in the
599 containing patches of outgoing messages will be encoded in the
600 first character set to which conversion from local encoding
600 first character set to which conversion from local encoding
601 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
601 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
602 conversion fails, the text in question is sent as is. Defaults to
602 conversion fails, the text in question is sent as is. Defaults to
603 empty (explicit) list.
603 empty (explicit) list.
604
604
605 Order of outgoing email character sets:
605 Order of outgoing email character sets:
606
606
607 1. ``us-ascii``: always first, regardless of settings
607 1. ``us-ascii``: always first, regardless of settings
608 2. ``email.charsets``: in order given by user
608 2. ``email.charsets``: in order given by user
609 3. ``ui.fallbackencoding``: if not in email.charsets
609 3. ``ui.fallbackencoding``: if not in email.charsets
610 4. ``$HGENCODING``: if not in email.charsets
610 4. ``$HGENCODING``: if not in email.charsets
611 5. ``utf-8``: always last, regardless of settings
611 5. ``utf-8``: always last, regardless of settings
612
612
613 Email example::
613 Email example::
614
614
615 [email]
615 [email]
616 from = Joseph User <joe.user@example.com>
616 from = Joseph User <joe.user@example.com>
617 method = /usr/sbin/sendmail
617 method = /usr/sbin/sendmail
618 # charsets for western Europeans
618 # charsets for western Europeans
619 # us-ascii, utf-8 omitted, as they are tried first and last
619 # us-ascii, utf-8 omitted, as they are tried first and last
620 charsets = iso-8859-1, iso-8859-15, windows-1252
620 charsets = iso-8859-1, iso-8859-15, windows-1252
621
621
622
622
623 ``extensions``
623 ``extensions``
624 --------------
624 --------------
625
625
626 Mercurial has an extension mechanism for adding new features. To
626 Mercurial has an extension mechanism for adding new features. To
627 enable an extension, create an entry for it in this section.
627 enable an extension, create an entry for it in this section.
628
628
629 If you know that the extension is already in Python's search path,
629 If you know that the extension is already in Python's search path,
630 you can give the name of the module, followed by ``=``, with nothing
630 you can give the name of the module, followed by ``=``, with nothing
631 after the ``=``.
631 after the ``=``.
632
632
633 Otherwise, give a name that you choose, followed by ``=``, followed by
633 Otherwise, give a name that you choose, followed by ``=``, followed by
634 the path to the ``.py`` file (including the file name extension) that
634 the path to the ``.py`` file (including the file name extension) that
635 defines the extension.
635 defines the extension.
636
636
637 To explicitly disable an extension that is enabled in an hgrc of
637 To explicitly disable an extension that is enabled in an hgrc of
638 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
638 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
639 or ``foo = !`` when path is not supplied.
639 or ``foo = !`` when path is not supplied.
640
640
641 Example for ``~/.hgrc``::
641 Example for ``~/.hgrc``::
642
642
643 [extensions]
643 [extensions]
644 # (the color extension will get loaded from Mercurial's path)
644 # (the color extension will get loaded from Mercurial's path)
645 color =
645 color =
646 # (this extension will get loaded from the file specified)
646 # (this extension will get loaded from the file specified)
647 myfeature = ~/.hgext/myfeature.py
647 myfeature = ~/.hgext/myfeature.py
648
648
649
649
650 ``format``
650 ``format``
651 ----------
651 ----------
652
652
653 ``usestore``
653 ``usestore``
654 Enable or disable the "store" repository format which improves
654 Enable or disable the "store" repository format which improves
655 compatibility with systems that fold case or otherwise mangle
655 compatibility with systems that fold case or otherwise mangle
656 filenames. Enabled by default. Disabling this option will allow
656 filenames. Enabled by default. Disabling this option will allow
657 you to store longer filenames in some situations at the expense of
657 you to store longer filenames in some situations at the expense of
658 compatibility and ensures that the on-disk format of newly created
658 compatibility and ensures that the on-disk format of newly created
659 repositories will be compatible with Mercurial before version 0.9.4.
659 repositories will be compatible with Mercurial before version 0.9.4.
660
660
661 ``usefncache``
661 ``usefncache``
662 Enable or disable the "fncache" repository format which enhances
662 Enable or disable the "fncache" repository format which enhances
663 the "store" repository format (which has to be enabled to use
663 the "store" repository format (which has to be enabled to use
664 fncache) to allow longer filenames and avoids using Windows
664 fncache) to allow longer filenames and avoids using Windows
665 reserved names, e.g. "nul". Enabled by default. Disabling this
665 reserved names, e.g. "nul". Enabled by default. Disabling this
666 option ensures that the on-disk format of newly created
666 option ensures that the on-disk format of newly created
667 repositories will be compatible with Mercurial before version 1.1.
667 repositories will be compatible with Mercurial before version 1.1.
668
668
669 ``dotencode``
669 ``dotencode``
670 Enable or disable the "dotencode" repository format which enhances
670 Enable or disable the "dotencode" repository format which enhances
671 the "fncache" repository format (which has to be enabled to use
671 the "fncache" repository format (which has to be enabled to use
672 dotencode) to avoid issues with filenames starting with ._ on
672 dotencode) to avoid issues with filenames starting with ._ on
673 Mac OS X and spaces on Windows. Enabled by default. Disabling this
673 Mac OS X and spaces on Windows. Enabled by default. Disabling this
674 option ensures that the on-disk format of newly created
674 option ensures that the on-disk format of newly created
675 repositories will be compatible with Mercurial before version 1.7.
675 repositories will be compatible with Mercurial before version 1.7.
676
676
677 ``graph``
677 ``graph``
678 ---------
678 ---------
679
679
680 Web graph view configuration. This section let you change graph
680 Web graph view configuration. This section let you change graph
681 elements display properties by branches, for instance to make the
681 elements display properties by branches, for instance to make the
682 ``default`` branch stand out.
682 ``default`` branch stand out.
683
683
684 Each line has the following format::
684 Each line has the following format::
685
685
686 <branch>.<argument> = <value>
686 <branch>.<argument> = <value>
687
687
688 where ``<branch>`` is the name of the branch being
688 where ``<branch>`` is the name of the branch being
689 customized. Example::
689 customized. Example::
690
690
691 [graph]
691 [graph]
692 # 2px width
692 # 2px width
693 default.width = 2
693 default.width = 2
694 # red color
694 # red color
695 default.color = FF0000
695 default.color = FF0000
696
696
697 Supported arguments:
697 Supported arguments:
698
698
699 ``width``
699 ``width``
700 Set branch edges width in pixels.
700 Set branch edges width in pixels.
701
701
702 ``color``
702 ``color``
703 Set branch edges color in hexadecimal RGB notation.
703 Set branch edges color in hexadecimal RGB notation.
704
704
705 ``hooks``
705 ``hooks``
706 ---------
706 ---------
707
707
708 Commands or Python functions that get automatically executed by
708 Commands or Python functions that get automatically executed by
709 various actions such as starting or finishing a commit. Multiple
709 various actions such as starting or finishing a commit. Multiple
710 hooks can be run for the same action by appending a suffix to the
710 hooks can be run for the same action by appending a suffix to the
711 action. Overriding a site-wide hook can be done by changing its
711 action. Overriding a site-wide hook can be done by changing its
712 value or setting it to an empty string. Hooks can be prioritized
712 value or setting it to an empty string. Hooks can be prioritized
713 by adding a prefix of ``priority`` to the hook name on a new line
713 by adding a prefix of ``priority`` to the hook name on a new line
714 and setting the priority. The default priority is 0 if
714 and setting the priority. The default priority is 0 if
715 not specified.
715 not specified.
716
716
717 Example ``.hg/hgrc``::
717 Example ``.hg/hgrc``::
718
718
719 [hooks]
719 [hooks]
720 # update working directory after adding changesets
720 # update working directory after adding changesets
721 changegroup.update = hg update
721 changegroup.update = hg update
722 # do not use the site-wide hook
722 # do not use the site-wide hook
723 incoming =
723 incoming =
724 incoming.email = /my/email/hook
724 incoming.email = /my/email/hook
725 incoming.autobuild = /my/build/hook
725 incoming.autobuild = /my/build/hook
726 # force autobuild hook to run before other incoming hooks
726 # force autobuild hook to run before other incoming hooks
727 priority.incoming.autobuild = 1
727 priority.incoming.autobuild = 1
728
728
729 Most hooks are run with environment variables set that give useful
729 Most hooks are run with environment variables set that give useful
730 additional information. For each hook below, the environment
730 additional information. For each hook below, the environment
731 variables it is passed are listed with names of the form ``$HG_foo``.
731 variables it is passed are listed with names of the form ``$HG_foo``.
732
732
733 ``changegroup``
733 ``changegroup``
734 Run after a changegroup has been added via push, pull or unbundle.
734 Run after a changegroup has been added via push, pull or unbundle.
735 ID of the first new changeset is in ``$HG_NODE``. URL from which
735 ID of the first new changeset is in ``$HG_NODE``. URL from which
736 changes came is in ``$HG_URL``.
736 changes came is in ``$HG_URL``.
737
737
738 ``commit``
738 ``commit``
739 Run after a changeset has been created in the local repository. ID
739 Run after a changeset has been created in the local repository. ID
740 of the newly created changeset is in ``$HG_NODE``. Parent changeset
740 of the newly created changeset is in ``$HG_NODE``. Parent changeset
741 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
741 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
742
742
743 ``incoming``
743 ``incoming``
744 Run after a changeset has been pulled, pushed, or unbundled into
744 Run after a changeset has been pulled, pushed, or unbundled into
745 the local repository. The ID of the newly arrived changeset is in
745 the local repository. The ID of the newly arrived changeset is in
746 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
746 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
747
747
748 ``outgoing``
748 ``outgoing``
749 Run after sending changes from local repository to another. ID of
749 Run after sending changes from local repository to another. ID of
750 first changeset sent is in ``$HG_NODE``. Source of operation is in
750 first changeset sent is in ``$HG_NODE``. Source of operation is in
751 ``$HG_SOURCE``; see "preoutgoing" hook for description.
751 ``$HG_SOURCE``; see "preoutgoing" hook for description.
752
752
753 ``post-<command>``
753 ``post-<command>``
754 Run after successful invocations of the associated command. The
754 Run after successful invocations of the associated command. The
755 contents of the command line are passed as ``$HG_ARGS`` and the result
755 contents of the command line are passed as ``$HG_ARGS`` and the result
756 code in ``$HG_RESULT``. Parsed command line arguments are passed as
756 code in ``$HG_RESULT``. Parsed command line arguments are passed as
757 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
757 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
758 the python data internally passed to <command>. ``$HG_OPTS`` is a
758 the python data internally passed to <command>. ``$HG_OPTS`` is a
759 dictionary of options (with unspecified options set to their defaults).
759 dictionary of options (with unspecified options set to their defaults).
760 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
760 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
761
761
762 ``pre-<command>``
762 ``pre-<command>``
763 Run before executing the associated command. The contents of the
763 Run before executing the associated command. The contents of the
764 command line are passed as ``$HG_ARGS``. Parsed command line arguments
764 command line are passed as ``$HG_ARGS``. Parsed command line arguments
765 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
765 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
766 representations of the data internally passed to <command>. ``$HG_OPTS``
766 representations of the data internally passed to <command>. ``$HG_OPTS``
767 is a dictionary of options (with unspecified options set to their
767 is a dictionary of options (with unspecified options set to their
768 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
768 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
769 failure, the command doesn't execute and Mercurial returns the failure
769 failure, the command doesn't execute and Mercurial returns the failure
770 code.
770 code.
771
771
772 ``prechangegroup``
772 ``prechangegroup``
773 Run before a changegroup is added via push, pull or unbundle. Exit
773 Run before a changegroup is added via push, pull or unbundle. Exit
774 status 0 allows the changegroup to proceed. Non-zero status will
774 status 0 allows the changegroup to proceed. Non-zero status will
775 cause the push, pull or unbundle to fail. URL from which changes
775 cause the push, pull or unbundle to fail. URL from which changes
776 will come is in ``$HG_URL``.
776 will come is in ``$HG_URL``.
777
777
778 ``precommit``
778 ``precommit``
779 Run before starting a local commit. Exit status 0 allows the
779 Run before starting a local commit. Exit status 0 allows the
780 commit to proceed. Non-zero status will cause the commit to fail.
780 commit to proceed. Non-zero status will cause the commit to fail.
781 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
781 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
782
782
783 ``prelistkeys``
783 ``prelistkeys``
784 Run before listing pushkeys (like bookmarks) in the
784 Run before listing pushkeys (like bookmarks) in the
785 repository. Non-zero status will cause failure. The key namespace is
785 repository. Non-zero status will cause failure. The key namespace is
786 in ``$HG_NAMESPACE``.
786 in ``$HG_NAMESPACE``.
787
787
788 ``preoutgoing``
788 ``preoutgoing``
789 Run before collecting changes to send from the local repository to
789 Run before collecting changes to send from the local repository to
790 another. Non-zero status will cause failure. This lets you prevent
790 another. Non-zero status will cause failure. This lets you prevent
791 pull over HTTP or SSH. Also prevents against local pull, push
791 pull over HTTP or SSH. Also prevents against local pull, push
792 (outbound) or bundle commands, but not effective, since you can
792 (outbound) or bundle commands, but not effective, since you can
793 just copy files instead then. Source of operation is in
793 just copy files instead then. Source of operation is in
794 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
794 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
795 SSH or HTTP repository. If "push", "pull" or "bundle", operation
795 SSH or HTTP repository. If "push", "pull" or "bundle", operation
796 is happening on behalf of repository on same system.
796 is happening on behalf of repository on same system.
797
797
798 ``prepushkey``
798 ``prepushkey``
799 Run before a pushkey (like a bookmark) is added to the
799 Run before a pushkey (like a bookmark) is added to the
800 repository. Non-zero status will cause the key to be rejected. The
800 repository. Non-zero status will cause the key to be rejected. The
801 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
801 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
802 the old value (if any) is in ``$HG_OLD``, and the new value is in
802 the old value (if any) is in ``$HG_OLD``, and the new value is in
803 ``$HG_NEW``.
803 ``$HG_NEW``.
804
804
805 ``pretag``
805 ``pretag``
806 Run before creating a tag. Exit status 0 allows the tag to be
806 Run before creating a tag. Exit status 0 allows the tag to be
807 created. Non-zero status will cause the tag to fail. ID of
807 created. Non-zero status will cause the tag to fail. ID of
808 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
808 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
809 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
809 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
810
810
811 ``pretxnopen``
811 ``pretxnopen``
812 Run before any new repository transaction is open. The reason for the
812 Run before any new repository transaction is open. The reason for the
813 transaction will be in ``$HG_TXNNAME`` and a unique identifier for the
813 transaction will be in ``$HG_TXNNAME`` and a unique identifier for the
814 transaction will be in ``HG_TXNID``. A non-zero status will prevent the
814 transaction will be in ``HG_TXNID``. A non-zero status will prevent the
815 transaction from being opened.
815 transaction from being opened.
816
816
817 ``pretxnclose``
817 ``pretxnclose``
818 Run right before the transaction is actually finalized. Any
818 Run right before the transaction is actually finalized. Any
819 repository change will be visible to the hook program. This lets you
819 repository change will be visible to the hook program. This lets you
820 validate the transaction content or change it. Exit status 0 allows
820 validate the transaction content or change it. Exit status 0 allows
821 the commit to proceed. Non-zero status will cause the transaction to
821 the commit to proceed. Non-zero status will cause the transaction to
822 be rolled back. The reason for the transaction opening will be in
822 be rolled back. The reason for the transaction opening will be in
823 ``$HG_TXNNAME`` and a unique identifier for the transaction will be in
823 ``$HG_TXNNAME`` and a unique identifier for the transaction will be in
824 ``HG_TXNID``. The rest of the available data will vary according the
824 ``HG_TXNID``. The rest of the available data will vary according the
825 transaction type. New changesets will add ``$HG_NODE`` (id of the
825 transaction type. New changesets will add ``$HG_NODE`` (id of the
826 first added changeset), ``$HG_URL`` and ``$HG_SOURCE`` variables,
826 first added changeset), ``$HG_URL`` and ``$HG_SOURCE`` variables,
827 bookmarks and phases changes will set ``HG_BOOKMARK_MOVED`` and
827 bookmarks and phases changes will set ``HG_BOOKMARK_MOVED`` and
828 ``HG_PHASES_MOVED`` to ``1``, etc.
828 ``HG_PHASES_MOVED`` to ``1``, etc.
829
829
830 ``txnclose``
830 ``txnclose``
831 Run after any repository transaction has been committed. At this
831 Run after any repository transaction has been committed. At this
832 point, the transaction can no longer be rolled back. The hook will run
832 point, the transaction can no longer be rolled back. The hook will run
833 after the lock is released. See ``pretxnclose`` docs for details about
833 after the lock is released. See ``pretxnclose`` docs for details about
834 available variables.
834 available variables.
835
835
836 ``txnabort``
836 ``txnabort``
837 Run when a transaction is aborted. See ``pretxnclose`` docs for details about
837 Run when a transaction is aborted. See ``pretxnclose`` docs for details about
838 available variables.
838 available variables.
839
839
840 ``pretxnchangegroup``
840 ``pretxnchangegroup``
841 Run after a changegroup has been added via push, pull or unbundle,
841 Run after a changegroup has been added via push, pull or unbundle,
842 but before the transaction has been committed. Changegroup is
842 but before the transaction has been committed. Changegroup is
843 visible to hook program. This lets you validate incoming changes
843 visible to hook program. This lets you validate incoming changes
844 before accepting them. Passed the ID of the first new changeset in
844 before accepting them. Passed the ID of the first new changeset in
845 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
845 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
846 status will cause the transaction to be rolled back and the push,
846 status will cause the transaction to be rolled back and the push,
847 pull or unbundle will fail. URL that was source of changes is in
847 pull or unbundle will fail. URL that was source of changes is in
848 ``$HG_URL``.
848 ``$HG_URL``.
849
849
850 ``pretxncommit``
850 ``pretxncommit``
851 Run after a changeset has been created but the transaction not yet
851 Run after a changeset has been created but the transaction not yet
852 committed. Changeset is visible to hook program. This lets you
852 committed. Changeset is visible to hook program. This lets you
853 validate commit message and changes. Exit status 0 allows the
853 validate commit message and changes. Exit status 0 allows the
854 commit to proceed. Non-zero status will cause the transaction to
854 commit to proceed. Non-zero status will cause the transaction to
855 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
855 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
856 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
856 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
857
857
858 ``preupdate``
858 ``preupdate``
859 Run before updating the working directory. Exit status 0 allows
859 Run before updating the working directory. Exit status 0 allows
860 the update to proceed. Non-zero status will prevent the update.
860 the update to proceed. Non-zero status will prevent the update.
861 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
861 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
862 of second new parent is in ``$HG_PARENT2``.
862 of second new parent is in ``$HG_PARENT2``.
863
863
864 ``listkeys``
864 ``listkeys``
865 Run after listing pushkeys (like bookmarks) in the repository. The
865 Run after listing pushkeys (like bookmarks) in the repository. The
866 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
866 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
867 dictionary containing the keys and values.
867 dictionary containing the keys and values.
868
868
869 ``pushkey``
869 ``pushkey``
870 Run after a pushkey (like a bookmark) is added to the
870 Run after a pushkey (like a bookmark) is added to the
871 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
871 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
872 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
872 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
873 value is in ``$HG_NEW``.
873 value is in ``$HG_NEW``.
874
874
875 ``tag``
875 ``tag``
876 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
876 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
877 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
877 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
878 repository if ``$HG_LOCAL=0``.
878 repository if ``$HG_LOCAL=0``.
879
879
880 ``update``
880 ``update``
881 Run after updating the working directory. Changeset ID of first
881 Run after updating the working directory. Changeset ID of first
882 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
882 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
883 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
883 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
884 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
884 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
885
885
886 .. note::
886 .. note::
887
887
888 It is generally better to use standard hooks rather than the
888 It is generally better to use standard hooks rather than the
889 generic pre- and post- command hooks as they are guaranteed to be
889 generic pre- and post- command hooks as they are guaranteed to be
890 called in the appropriate contexts for influencing transactions.
890 called in the appropriate contexts for influencing transactions.
891 Also, hooks like "commit" will be called in all contexts that
891 Also, hooks like "commit" will be called in all contexts that
892 generate a commit (e.g. tag) and not just the commit command.
892 generate a commit (e.g. tag) and not just the commit command.
893
893
894 .. note::
894 .. note::
895
895
896 Environment variables with empty values may not be passed to
896 Environment variables with empty values may not be passed to
897 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
897 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
898 will have an empty value under Unix-like platforms for non-merge
898 will have an empty value under Unix-like platforms for non-merge
899 changesets, while it will not be available at all under Windows.
899 changesets, while it will not be available at all under Windows.
900
900
901 The syntax for Python hooks is as follows::
901 The syntax for Python hooks is as follows::
902
902
903 hookname = python:modulename.submodule.callable
903 hookname = python:modulename.submodule.callable
904 hookname = python:/path/to/python/module.py:callable
904 hookname = python:/path/to/python/module.py:callable
905
905
906 Python hooks are run within the Mercurial process. Each hook is
906 Python hooks are run within the Mercurial process. Each hook is
907 called with at least three keyword arguments: a ui object (keyword
907 called with at least three keyword arguments: a ui object (keyword
908 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
908 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
909 keyword that tells what kind of hook is used. Arguments listed as
909 keyword that tells what kind of hook is used. Arguments listed as
910 environment variables above are passed as keyword arguments, with no
910 environment variables above are passed as keyword arguments, with no
911 ``HG_`` prefix, and names in lower case.
911 ``HG_`` prefix, and names in lower case.
912
912
913 If a Python hook returns a "true" value or raises an exception, this
913 If a Python hook returns a "true" value or raises an exception, this
914 is treated as a failure.
914 is treated as a failure.
915
915
916
916
917 ``hostfingerprints``
917 ``hostfingerprints``
918 --------------------
918 --------------------
919
919
920 Fingerprints of the certificates of known HTTPS servers.
920 Fingerprints of the certificates of known HTTPS servers.
921 A HTTPS connection to a server with a fingerprint configured here will
921 A HTTPS connection to a server with a fingerprint configured here will
922 only succeed if the servers certificate matches the fingerprint.
922 only succeed if the servers certificate matches the fingerprint.
923 This is very similar to how ssh known hosts works.
923 This is very similar to how ssh known hosts works.
924 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
924 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
925 The CA chain and web.cacerts is not used for servers with a fingerprint.
925 The CA chain and web.cacerts is not used for servers with a fingerprint.
926
926
927 For example::
927 For example::
928
928
929 [hostfingerprints]
929 [hostfingerprints]
930 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
930 hg.intevation.org = fa:1f:d9:48:f1:e7:74:30:38:8d:d8:58:b6:94:b8:58:28:7d:8b:d0
931
931
932 This feature is only supported when using Python 2.6 or later.
932 This feature is only supported when using Python 2.6 or later.
933
933
934
934
935 ``http_proxy``
935 ``http_proxy``
936 --------------
936 --------------
937
937
938 Used to access web-based Mercurial repositories through a HTTP
938 Used to access web-based Mercurial repositories through a HTTP
939 proxy.
939 proxy.
940
940
941 ``host``
941 ``host``
942 Host name and (optional) port of the proxy server, for example
942 Host name and (optional) port of the proxy server, for example
943 "myproxy:8000".
943 "myproxy:8000".
944
944
945 ``no``
945 ``no``
946 Optional. Comma-separated list of host names that should bypass
946 Optional. Comma-separated list of host names that should bypass
947 the proxy.
947 the proxy.
948
948
949 ``passwd``
949 ``passwd``
950 Optional. Password to authenticate with at the proxy server.
950 Optional. Password to authenticate with at the proxy server.
951
951
952 ``user``
952 ``user``
953 Optional. User name to authenticate with at the proxy server.
953 Optional. User name to authenticate with at the proxy server.
954
954
955 ``always``
955 ``always``
956 Optional. Always use the proxy, even for localhost and any entries
956 Optional. Always use the proxy, even for localhost and any entries
957 in ``http_proxy.no``. True or False. Default: False.
957 in ``http_proxy.no``. True or False. Default: False.
958
958
959 ``merge-patterns``
959 ``merge-patterns``
960 ------------------
960 ------------------
961
961
962 This section specifies merge tools to associate with particular file
962 This section specifies merge tools to associate with particular file
963 patterns. Tools matched here will take precedence over the default
963 patterns. Tools matched here will take precedence over the default
964 merge tool. Patterns are globs by default, rooted at the repository
964 merge tool. Patterns are globs by default, rooted at the repository
965 root.
965 root.
966
966
967 Example::
967 Example::
968
968
969 [merge-patterns]
969 [merge-patterns]
970 **.c = kdiff3
970 **.c = kdiff3
971 **.jpg = myimgmerge
971 **.jpg = myimgmerge
972
972
973 ``merge-tools``
973 ``merge-tools``
974 ---------------
974 ---------------
975
975
976 This section configures external merge tools to use for file-level
976 This section configures external merge tools to use for file-level
977 merges. This section has likely been preconfigured at install time.
977 merges. This section has likely been preconfigured at install time.
978 Use :hg:`config merge-tools` to check the existing configuration.
978 Use :hg:`config merge-tools` to check the existing configuration.
979 Also see :hg:`help merge-tools` for more details.
979 Also see :hg:`help merge-tools` for more details.
980
980
981 Example ``~/.hgrc``::
981 Example ``~/.hgrc``::
982
982
983 [merge-tools]
983 [merge-tools]
984 # Override stock tool location
984 # Override stock tool location
985 kdiff3.executable = ~/bin/kdiff3
985 kdiff3.executable = ~/bin/kdiff3
986 # Specify command line
986 # Specify command line
987 kdiff3.args = $base $local $other -o $output
987 kdiff3.args = $base $local $other -o $output
988 # Give higher priority
988 # Give higher priority
989 kdiff3.priority = 1
989 kdiff3.priority = 1
990
990
991 # Changing the priority of preconfigured tool
991 # Changing the priority of preconfigured tool
992 vimdiff.priority = 0
992 vimdiff.priority = 0
993
993
994 # Define new tool
994 # Define new tool
995 myHtmlTool.args = -m $local $other $base $output
995 myHtmlTool.args = -m $local $other $base $output
996 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
996 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
997 myHtmlTool.priority = 1
997 myHtmlTool.priority = 1
998
998
999 Supported arguments:
999 Supported arguments:
1000
1000
1001 ``priority``
1001 ``priority``
1002 The priority in which to evaluate this tool.
1002 The priority in which to evaluate this tool.
1003 Default: 0.
1003 Default: 0.
1004
1004
1005 ``executable``
1005 ``executable``
1006 Either just the name of the executable or its pathname. On Windows,
1006 Either just the name of the executable or its pathname. On Windows,
1007 the path can use environment variables with ${ProgramFiles} syntax.
1007 the path can use environment variables with ${ProgramFiles} syntax.
1008 Default: the tool name.
1008 Default: the tool name.
1009
1009
1010 ``args``
1010 ``args``
1011 The arguments to pass to the tool executable. You can refer to the
1011 The arguments to pass to the tool executable. You can refer to the
1012 files being merged as well as the output file through these
1012 files being merged as well as the output file through these
1013 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
1013 variables: ``$base``, ``$local``, ``$other``, ``$output``. The meaning
1014 of ``$local`` and ``$other`` can vary depending on which action is being
1014 of ``$local`` and ``$other`` can vary depending on which action is being
1015 performed. During and update or merge, ``$local`` represents the original
1015 performed. During and update or merge, ``$local`` represents the original
1016 state of the file, while ``$other`` represents the commit you are updating
1016 state of the file, while ``$other`` represents the commit you are updating
1017 to or the commit you are merging with. During a rebase ``$local``
1017 to or the commit you are merging with. During a rebase ``$local``
1018 represents the destination of the rebase, and ``$other`` represents the
1018 represents the destination of the rebase, and ``$other`` represents the
1019 commit being rebased.
1019 commit being rebased.
1020 Default: ``$local $base $other``
1020 Default: ``$local $base $other``
1021
1021
1022 ``premerge``
1022 ``premerge``
1023 Attempt to run internal non-interactive 3-way merge tool before
1023 Attempt to run internal non-interactive 3-way merge tool before
1024 launching external tool. Options are ``true``, ``false``, ``keep`` or
1024 launching external tool. Options are ``true``, ``false``, ``keep`` or
1025 ``keep-merge3``. The ``keep`` option will leave markers in the file if the
1025 ``keep-merge3``. The ``keep`` option will leave markers in the file if the
1026 premerge fails. The ``keep-merge3`` will do the same but include information
1026 premerge fails. The ``keep-merge3`` will do the same but include information
1027 about the base of the merge in the marker (see internal :merge3 in
1027 about the base of the merge in the marker (see internal :merge3 in
1028 :hg:`help merge-tools`).
1028 :hg:`help merge-tools`).
1029 Default: True
1029 Default: True
1030
1030
1031 ``binary``
1031 ``binary``
1032 This tool can merge binary files. Defaults to False, unless tool
1032 This tool can merge binary files. Defaults to False, unless tool
1033 was selected by file pattern match.
1033 was selected by file pattern match.
1034
1034
1035 ``symlink``
1035 ``symlink``
1036 This tool can merge symlinks. Defaults to False, even if tool was
1036 This tool can merge symlinks. Defaults to False, even if tool was
1037 selected by file pattern match.
1037 selected by file pattern match.
1038
1038
1039 ``check``
1039 ``check``
1040 A list of merge success-checking options:
1040 A list of merge success-checking options:
1041
1041
1042 ``changed``
1042 ``changed``
1043 Ask whether merge was successful when the merged file shows no changes.
1043 Ask whether merge was successful when the merged file shows no changes.
1044 ``conflicts``
1044 ``conflicts``
1045 Check whether there are conflicts even though the tool reported success.
1045 Check whether there are conflicts even though the tool reported success.
1046 ``prompt``
1046 ``prompt``
1047 Always prompt for merge success, regardless of success reported by tool.
1047 Always prompt for merge success, regardless of success reported by tool.
1048
1048
1049 ``fixeol``
1049 ``fixeol``
1050 Attempt to fix up EOL changes caused by the merge tool.
1050 Attempt to fix up EOL changes caused by the merge tool.
1051 Default: False
1051 Default: False
1052
1052
1053 ``gui``
1053 ``gui``
1054 This tool requires a graphical interface to run. Default: False
1054 This tool requires a graphical interface to run. Default: False
1055
1055
1056 ``regkey``
1056 ``regkey``
1057 Windows registry key which describes install location of this
1057 Windows registry key which describes install location of this
1058 tool. Mercurial will search for this key first under
1058 tool. Mercurial will search for this key first under
1059 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
1059 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
1060 Default: None
1060 Default: None
1061
1061
1062 ``regkeyalt``
1062 ``regkeyalt``
1063 An alternate Windows registry key to try if the first key is not
1063 An alternate Windows registry key to try if the first key is not
1064 found. The alternate key uses the same ``regname`` and ``regappend``
1064 found. The alternate key uses the same ``regname`` and ``regappend``
1065 semantics of the primary key. The most common use for this key
1065 semantics of the primary key. The most common use for this key
1066 is to search for 32bit applications on 64bit operating systems.
1066 is to search for 32bit applications on 64bit operating systems.
1067 Default: None
1067 Default: None
1068
1068
1069 ``regname``
1069 ``regname``
1070 Name of value to read from specified registry key. Defaults to the
1070 Name of value to read from specified registry key. Defaults to the
1071 unnamed (default) value.
1071 unnamed (default) value.
1072
1072
1073 ``regappend``
1073 ``regappend``
1074 String to append to the value read from the registry, typically
1074 String to append to the value read from the registry, typically
1075 the executable name of the tool.
1075 the executable name of the tool.
1076 Default: None
1076 Default: None
1077
1077
1078
1078
1079 ``patch``
1079 ``patch``
1080 ---------
1080 ---------
1081
1081
1082 Settings used when applying patches, for instance through the 'import'
1082 Settings used when applying patches, for instance through the 'import'
1083 command or with Mercurial Queues extension.
1083 command or with Mercurial Queues extension.
1084
1084
1085 ``eol``
1085 ``eol``
1086 When set to 'strict' patch content and patched files end of lines
1086 When set to 'strict' patch content and patched files end of lines
1087 are preserved. When set to ``lf`` or ``crlf``, both files end of
1087 are preserved. When set to ``lf`` or ``crlf``, both files end of
1088 lines are ignored when patching and the result line endings are
1088 lines are ignored when patching and the result line endings are
1089 normalized to either LF (Unix) or CRLF (Windows). When set to
1089 normalized to either LF (Unix) or CRLF (Windows). When set to
1090 ``auto``, end of lines are again ignored while patching but line
1090 ``auto``, end of lines are again ignored while patching but line
1091 endings in patched files are normalized to their original setting
1091 endings in patched files are normalized to their original setting
1092 on a per-file basis. If target file does not exist or has no end
1092 on a per-file basis. If target file does not exist or has no end
1093 of line, patch line endings are preserved.
1093 of line, patch line endings are preserved.
1094 Default: strict.
1094 Default: strict.
1095
1095
1096 ``fuzz``
1097 The number of lines of 'fuzz' to allow when applying patches. This
1098 controls how much context the patcher is allowed to ignore when
1099 trying to apply a patch.
1100 Default: 2
1096
1101
1097 ``paths``
1102 ``paths``
1098 ---------
1103 ---------
1099
1104
1100 Assigns symbolic names to repositories. The left side is the
1105 Assigns symbolic names to repositories. The left side is the
1101 symbolic name, and the right gives the directory or URL that is the
1106 symbolic name, and the right gives the directory or URL that is the
1102 location of the repository. Default paths can be declared by setting
1107 location of the repository. Default paths can be declared by setting
1103 the following entries.
1108 the following entries.
1104
1109
1105 ``default``
1110 ``default``
1106 Directory or URL to use when pulling if no source is specified.
1111 Directory or URL to use when pulling if no source is specified.
1107 Default is set to repository from which the current repository was
1112 Default is set to repository from which the current repository was
1108 cloned.
1113 cloned.
1109
1114
1110 ``default-push``
1115 ``default-push``
1111 Optional. Directory or URL to use when pushing if no destination
1116 Optional. Directory or URL to use when pushing if no destination
1112 is specified.
1117 is specified.
1113
1118
1114 Custom paths can be defined by assigning the path to a name that later can be
1119 Custom paths can be defined by assigning the path to a name that later can be
1115 used from the command line. Example::
1120 used from the command line. Example::
1116
1121
1117 [paths]
1122 [paths]
1118 my_path = http://example.com/path
1123 my_path = http://example.com/path
1119
1124
1120 To push to the path defined in ``my_path`` run the command::
1125 To push to the path defined in ``my_path`` run the command::
1121
1126
1122 hg push my_path
1127 hg push my_path
1123
1128
1124
1129
1125 ``phases``
1130 ``phases``
1126 ----------
1131 ----------
1127
1132
1128 Specifies default handling of phases. See :hg:`help phases` for more
1133 Specifies default handling of phases. See :hg:`help phases` for more
1129 information about working with phases.
1134 information about working with phases.
1130
1135
1131 ``publish``
1136 ``publish``
1132 Controls draft phase behavior when working as a server. When true,
1137 Controls draft phase behavior when working as a server. When true,
1133 pushed changesets are set to public in both client and server and
1138 pushed changesets are set to public in both client and server and
1134 pulled or cloned changesets are set to public in the client.
1139 pulled or cloned changesets are set to public in the client.
1135 Default: True
1140 Default: True
1136
1141
1137 ``new-commit``
1142 ``new-commit``
1138 Phase of newly-created commits.
1143 Phase of newly-created commits.
1139 Default: draft
1144 Default: draft
1140
1145
1141 ``checksubrepos``
1146 ``checksubrepos``
1142 Check the phase of the current revision of each subrepository. Allowed
1147 Check the phase of the current revision of each subrepository. Allowed
1143 values are "ignore", "follow" and "abort". For settings other than
1148 values are "ignore", "follow" and "abort". For settings other than
1144 "ignore", the phase of the current revision of each subrepository is
1149 "ignore", the phase of the current revision of each subrepository is
1145 checked before committing the parent repository. If any of those phases is
1150 checked before committing the parent repository. If any of those phases is
1146 greater than the phase of the parent repository (e.g. if a subrepo is in a
1151 greater than the phase of the parent repository (e.g. if a subrepo is in a
1147 "secret" phase while the parent repo is in "draft" phase), the commit is
1152 "secret" phase while the parent repo is in "draft" phase), the commit is
1148 either aborted (if checksubrepos is set to "abort") or the higher phase is
1153 either aborted (if checksubrepos is set to "abort") or the higher phase is
1149 used for the parent repository commit (if set to "follow").
1154 used for the parent repository commit (if set to "follow").
1150 Default: "follow"
1155 Default: "follow"
1151
1156
1152
1157
1153 ``profiling``
1158 ``profiling``
1154 -------------
1159 -------------
1155
1160
1156 Specifies profiling type, format, and file output. Two profilers are
1161 Specifies profiling type, format, and file output. Two profilers are
1157 supported: an instrumenting profiler (named ``ls``), and a sampling
1162 supported: an instrumenting profiler (named ``ls``), and a sampling
1158 profiler (named ``stat``).
1163 profiler (named ``stat``).
1159
1164
1160 In this section description, 'profiling data' stands for the raw data
1165 In this section description, 'profiling data' stands for the raw data
1161 collected during profiling, while 'profiling report' stands for a
1166 collected during profiling, while 'profiling report' stands for a
1162 statistical text report generated from the profiling data. The
1167 statistical text report generated from the profiling data. The
1163 profiling is done using lsprof.
1168 profiling is done using lsprof.
1164
1169
1165 ``type``
1170 ``type``
1166 The type of profiler to use.
1171 The type of profiler to use.
1167 Default: ls.
1172 Default: ls.
1168
1173
1169 ``ls``
1174 ``ls``
1170 Use Python's built-in instrumenting profiler. This profiler
1175 Use Python's built-in instrumenting profiler. This profiler
1171 works on all platforms, but each line number it reports is the
1176 works on all platforms, but each line number it reports is the
1172 first line of a function. This restriction makes it difficult to
1177 first line of a function. This restriction makes it difficult to
1173 identify the expensive parts of a non-trivial function.
1178 identify the expensive parts of a non-trivial function.
1174 ``stat``
1179 ``stat``
1175 Use a third-party statistical profiler, statprof. This profiler
1180 Use a third-party statistical profiler, statprof. This profiler
1176 currently runs only on Unix systems, and is most useful for
1181 currently runs only on Unix systems, and is most useful for
1177 profiling commands that run for longer than about 0.1 seconds.
1182 profiling commands that run for longer than about 0.1 seconds.
1178
1183
1179 ``format``
1184 ``format``
1180 Profiling format. Specific to the ``ls`` instrumenting profiler.
1185 Profiling format. Specific to the ``ls`` instrumenting profiler.
1181 Default: text.
1186 Default: text.
1182
1187
1183 ``text``
1188 ``text``
1184 Generate a profiling report. When saving to a file, it should be
1189 Generate a profiling report. When saving to a file, it should be
1185 noted that only the report is saved, and the profiling data is
1190 noted that only the report is saved, and the profiling data is
1186 not kept.
1191 not kept.
1187 ``kcachegrind``
1192 ``kcachegrind``
1188 Format profiling data for kcachegrind use: when saving to a
1193 Format profiling data for kcachegrind use: when saving to a
1189 file, the generated file can directly be loaded into
1194 file, the generated file can directly be loaded into
1190 kcachegrind.
1195 kcachegrind.
1191
1196
1192 ``frequency``
1197 ``frequency``
1193 Sampling frequency. Specific to the ``stat`` sampling profiler.
1198 Sampling frequency. Specific to the ``stat`` sampling profiler.
1194 Default: 1000.
1199 Default: 1000.
1195
1200
1196 ``output``
1201 ``output``
1197 File path where profiling data or report should be saved. If the
1202 File path where profiling data or report should be saved. If the
1198 file exists, it is replaced. Default: None, data is printed on
1203 file exists, it is replaced. Default: None, data is printed on
1199 stderr
1204 stderr
1200
1205
1201 ``sort``
1206 ``sort``
1202 Sort field. Specific to the ``ls`` instrumenting profiler.
1207 Sort field. Specific to the ``ls`` instrumenting profiler.
1203 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1208 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1204 ``inlinetime``.
1209 ``inlinetime``.
1205 Default: inlinetime.
1210 Default: inlinetime.
1206
1211
1207 ``limit``
1212 ``limit``
1208 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1213 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1209 Default: 30.
1214 Default: 30.
1210
1215
1211 ``nested``
1216 ``nested``
1212 Show at most this number of lines of drill-down info after each main entry.
1217 Show at most this number of lines of drill-down info after each main entry.
1213 This can help explain the difference between Total and Inline.
1218 This can help explain the difference between Total and Inline.
1214 Specific to the ``ls`` instrumenting profiler.
1219 Specific to the ``ls`` instrumenting profiler.
1215 Default: 5.
1220 Default: 5.
1216
1221
1217 ``progress``
1222 ``progress``
1218 ------------
1223 ------------
1219
1224
1220 Mercurial commands can draw progress bars that are as informative as
1225 Mercurial commands can draw progress bars that are as informative as
1221 possible. Some progress bars only offer indeterminate information, while others
1226 possible. Some progress bars only offer indeterminate information, while others
1222 have a definite end point.
1227 have a definite end point.
1223
1228
1224 ``delay``
1229 ``delay``
1225 Number of seconds (float) before showing the progress bar. (default: 3)
1230 Number of seconds (float) before showing the progress bar. (default: 3)
1226
1231
1227 ``changedelay``
1232 ``changedelay``
1228 Minimum delay before showing a new topic. When set to less than 3 * refresh,
1233 Minimum delay before showing a new topic. When set to less than 3 * refresh,
1229 that value will be used instead. (default: 1)
1234 that value will be used instead. (default: 1)
1230
1235
1231 ``refresh``
1236 ``refresh``
1232 Time in seconds between refreshes of the progress bar. (default: 0.1)
1237 Time in seconds between refreshes of the progress bar. (default: 0.1)
1233
1238
1234 ``format``
1239 ``format``
1235 Format of the progress bar.
1240 Format of the progress bar.
1236
1241
1237 Valid entries for the format field are ``topic``, ``bar``, ``number``,
1242 Valid entries for the format field are ``topic``, ``bar``, ``number``,
1238 ``unit``, ``estimate``, speed, and item. item defaults to the last 20
1243 ``unit``, ``estimate``, speed, and item. item defaults to the last 20
1239 characters of the item, but this can be changed by adding either ``-<num>``
1244 characters of the item, but this can be changed by adding either ``-<num>``
1240 which would take the last num characters, or ``+<num>`` for the first num
1245 which would take the last num characters, or ``+<num>`` for the first num
1241 characters.
1246 characters.
1242
1247
1243 (default: Topic bar number estimate)
1248 (default: Topic bar number estimate)
1244
1249
1245 ``width``
1250 ``width``
1246 If set, the maximum width of the progress information (that is, min(width,
1251 If set, the maximum width of the progress information (that is, min(width,
1247 term width) will be used)
1252 term width) will be used)
1248
1253
1249 ``clear-complete``
1254 ``clear-complete``
1250 clear the progress bar after it's done (default to True)
1255 clear the progress bar after it's done (default to True)
1251
1256
1252 ``disable``
1257 ``disable``
1253 If true, don't show a progress bar
1258 If true, don't show a progress bar
1254
1259
1255 ``assume-tty``
1260 ``assume-tty``
1256 If true, ALWAYS show a progress bar, unless disable is given
1261 If true, ALWAYS show a progress bar, unless disable is given
1257
1262
1258 ``revsetalias``
1263 ``revsetalias``
1259 ---------------
1264 ---------------
1260
1265
1261 Alias definitions for revsets. See :hg:`help revsets` for details.
1266 Alias definitions for revsets. See :hg:`help revsets` for details.
1262
1267
1263 ``server``
1268 ``server``
1264 ----------
1269 ----------
1265
1270
1266 Controls generic server settings.
1271 Controls generic server settings.
1267
1272
1268 ``uncompressed``
1273 ``uncompressed``
1269 Whether to allow clients to clone a repository using the
1274 Whether to allow clients to clone a repository using the
1270 uncompressed streaming protocol. This transfers about 40% more
1275 uncompressed streaming protocol. This transfers about 40% more
1271 data than a regular clone, but uses less memory and CPU on both
1276 data than a regular clone, but uses less memory and CPU on both
1272 server and client. Over a LAN (100 Mbps or better) or a very fast
1277 server and client. Over a LAN (100 Mbps or better) or a very fast
1273 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1278 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1274 regular clone. Over most WAN connections (anything slower than
1279 regular clone. Over most WAN connections (anything slower than
1275 about 6 Mbps), uncompressed streaming is slower, because of the
1280 about 6 Mbps), uncompressed streaming is slower, because of the
1276 extra data transfer overhead. This mode will also temporarily hold
1281 extra data transfer overhead. This mode will also temporarily hold
1277 the write lock while determining what data to transfer.
1282 the write lock while determining what data to transfer.
1278 Default is True.
1283 Default is True.
1279
1284
1280 ``preferuncompressed``
1285 ``preferuncompressed``
1281 When set, clients will try to use the uncompressed streaming
1286 When set, clients will try to use the uncompressed streaming
1282 protocol. Default is False.
1287 protocol. Default is False.
1283
1288
1284 ``validate``
1289 ``validate``
1285 Whether to validate the completeness of pushed changesets by
1290 Whether to validate the completeness of pushed changesets by
1286 checking that all new file revisions specified in manifests are
1291 checking that all new file revisions specified in manifests are
1287 present. Default is False.
1292 present. Default is False.
1288
1293
1289 ``smtp``
1294 ``smtp``
1290 --------
1295 --------
1291
1296
1292 Configuration for extensions that need to send email messages.
1297 Configuration for extensions that need to send email messages.
1293
1298
1294 ``host``
1299 ``host``
1295 Host name of mail server, e.g. "mail.example.com".
1300 Host name of mail server, e.g. "mail.example.com".
1296
1301
1297 ``port``
1302 ``port``
1298 Optional. Port to connect to on mail server. Default: 465 (if
1303 Optional. Port to connect to on mail server. Default: 465 (if
1299 ``tls`` is smtps) or 25 (otherwise).
1304 ``tls`` is smtps) or 25 (otherwise).
1300
1305
1301 ``tls``
1306 ``tls``
1302 Optional. Method to enable TLS when connecting to mail server: starttls,
1307 Optional. Method to enable TLS when connecting to mail server: starttls,
1303 smtps or none. Default: none.
1308 smtps or none. Default: none.
1304
1309
1305 ``verifycert``
1310 ``verifycert``
1306 Optional. Verification for the certificate of mail server, when
1311 Optional. Verification for the certificate of mail server, when
1307 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1312 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1308 "strict" or "loose", the certificate is verified as same as the
1313 "strict" or "loose", the certificate is verified as same as the
1309 verification for HTTPS connections (see ``[hostfingerprints]`` and
1314 verification for HTTPS connections (see ``[hostfingerprints]`` and
1310 ``[web] cacerts`` also). For "strict", sending email is also
1315 ``[web] cacerts`` also). For "strict", sending email is also
1311 aborted, if there is no configuration for mail server in
1316 aborted, if there is no configuration for mail server in
1312 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1317 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1313 :hg:`email` overwrites this as "loose". Default: "strict".
1318 :hg:`email` overwrites this as "loose". Default: "strict".
1314
1319
1315 ``username``
1320 ``username``
1316 Optional. User name for authenticating with the SMTP server.
1321 Optional. User name for authenticating with the SMTP server.
1317 Default: none.
1322 Default: none.
1318
1323
1319 ``password``
1324 ``password``
1320 Optional. Password for authenticating with the SMTP server. If not
1325 Optional. Password for authenticating with the SMTP server. If not
1321 specified, interactive sessions will prompt the user for a
1326 specified, interactive sessions will prompt the user for a
1322 password; non-interactive sessions will fail. Default: none.
1327 password; non-interactive sessions will fail. Default: none.
1323
1328
1324 ``local_hostname``
1329 ``local_hostname``
1325 Optional. It's the hostname that the sender can use to identify
1330 Optional. It's the hostname that the sender can use to identify
1326 itself to the MTA.
1331 itself to the MTA.
1327
1332
1328
1333
1329 ``subpaths``
1334 ``subpaths``
1330 ------------
1335 ------------
1331
1336
1332 Subrepository source URLs can go stale if a remote server changes name
1337 Subrepository source URLs can go stale if a remote server changes name
1333 or becomes temporarily unavailable. This section lets you define
1338 or becomes temporarily unavailable. This section lets you define
1334 rewrite rules of the form::
1339 rewrite rules of the form::
1335
1340
1336 <pattern> = <replacement>
1341 <pattern> = <replacement>
1337
1342
1338 where ``pattern`` is a regular expression matching a subrepository
1343 where ``pattern`` is a regular expression matching a subrepository
1339 source URL and ``replacement`` is the replacement string used to
1344 source URL and ``replacement`` is the replacement string used to
1340 rewrite it. Groups can be matched in ``pattern`` and referenced in
1345 rewrite it. Groups can be matched in ``pattern`` and referenced in
1341 ``replacements``. For instance::
1346 ``replacements``. For instance::
1342
1347
1343 http://server/(.*)-hg/ = http://hg.server/\1/
1348 http://server/(.*)-hg/ = http://hg.server/\1/
1344
1349
1345 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1350 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1346
1351
1347 Relative subrepository paths are first made absolute, and the
1352 Relative subrepository paths are first made absolute, and the
1348 rewrite rules are then applied on the full (absolute) path. The rules
1353 rewrite rules are then applied on the full (absolute) path. The rules
1349 are applied in definition order.
1354 are applied in definition order.
1350
1355
1351 ``trusted``
1356 ``trusted``
1352 -----------
1357 -----------
1353
1358
1354 Mercurial will not use the settings in the
1359 Mercurial will not use the settings in the
1355 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1360 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1356 user or to a trusted group, as various hgrc features allow arbitrary
1361 user or to a trusted group, as various hgrc features allow arbitrary
1357 commands to be run. This issue is often encountered when configuring
1362 commands to be run. This issue is often encountered when configuring
1358 hooks or extensions for shared repositories or servers. However,
1363 hooks or extensions for shared repositories or servers. However,
1359 the web interface will use some safe settings from the ``[web]``
1364 the web interface will use some safe settings from the ``[web]``
1360 section.
1365 section.
1361
1366
1362 This section specifies what users and groups are trusted. The
1367 This section specifies what users and groups are trusted. The
1363 current user is always trusted. To trust everybody, list a user or a
1368 current user is always trusted. To trust everybody, list a user or a
1364 group with name ``*``. These settings must be placed in an
1369 group with name ``*``. These settings must be placed in an
1365 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1370 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1366 user or service running Mercurial.
1371 user or service running Mercurial.
1367
1372
1368 ``users``
1373 ``users``
1369 Comma-separated list of trusted users.
1374 Comma-separated list of trusted users.
1370
1375
1371 ``groups``
1376 ``groups``
1372 Comma-separated list of trusted groups.
1377 Comma-separated list of trusted groups.
1373
1378
1374
1379
1375 ``ui``
1380 ``ui``
1376 ------
1381 ------
1377
1382
1378 User interface controls.
1383 User interface controls.
1379
1384
1380 ``archivemeta``
1385 ``archivemeta``
1381 Whether to include the .hg_archival.txt file containing meta data
1386 Whether to include the .hg_archival.txt file containing meta data
1382 (hashes for the repository base and for tip) in archives created
1387 (hashes for the repository base and for tip) in archives created
1383 by the :hg:`archive` command or downloaded via hgweb.
1388 by the :hg:`archive` command or downloaded via hgweb.
1384 Default is True.
1389 Default is True.
1385
1390
1386 ``askusername``
1391 ``askusername``
1387 Whether to prompt for a username when committing. If True, and
1392 Whether to prompt for a username when committing. If True, and
1388 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1393 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1389 be prompted to enter a username. If no username is entered, the
1394 be prompted to enter a username. If no username is entered, the
1390 default ``USER@HOST`` is used instead.
1395 default ``USER@HOST`` is used instead.
1391 Default is False.
1396 Default is False.
1392
1397
1393 ``commitsubrepos``
1398 ``commitsubrepos``
1394 Whether to commit modified subrepositories when committing the
1399 Whether to commit modified subrepositories when committing the
1395 parent repository. If False and one subrepository has uncommitted
1400 parent repository. If False and one subrepository has uncommitted
1396 changes, abort the commit.
1401 changes, abort the commit.
1397 Default is False.
1402 Default is False.
1398
1403
1399 ``debug``
1404 ``debug``
1400 Print debugging information. True or False. Default is False.
1405 Print debugging information. True or False. Default is False.
1401
1406
1402 ``editor``
1407 ``editor``
1403 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1408 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1404
1409
1405 ``fallbackencoding``
1410 ``fallbackencoding``
1406 Encoding to try if it's not possible to decode the changelog using
1411 Encoding to try if it's not possible to decode the changelog using
1407 UTF-8. Default is ISO-8859-1.
1412 UTF-8. Default is ISO-8859-1.
1408
1413
1409 ``ignore``
1414 ``ignore``
1410 A file to read per-user ignore patterns from. This file should be
1415 A file to read per-user ignore patterns from. This file should be
1411 in the same format as a repository-wide .hgignore file. Filenames
1416 in the same format as a repository-wide .hgignore file. Filenames
1412 are relative to the repository root. This option supports hook syntax,
1417 are relative to the repository root. This option supports hook syntax,
1413 so if you want to specify multiple ignore files, you can do so by
1418 so if you want to specify multiple ignore files, you can do so by
1414 setting something like ``ignore.other = ~/.hgignore2``. For details
1419 setting something like ``ignore.other = ~/.hgignore2``. For details
1415 of the ignore file format, see the ``hgignore(5)`` man page.
1420 of the ignore file format, see the ``hgignore(5)`` man page.
1416
1421
1417 ``interactive``
1422 ``interactive``
1418 Allow to prompt the user. True or False. Default is True.
1423 Allow to prompt the user. True or False. Default is True.
1419
1424
1420 ``logtemplate``
1425 ``logtemplate``
1421 Template string for commands that print changesets.
1426 Template string for commands that print changesets.
1422
1427
1423 ``merge``
1428 ``merge``
1424 The conflict resolution program to use during a manual merge.
1429 The conflict resolution program to use during a manual merge.
1425 For more information on merge tools see :hg:`help merge-tools`.
1430 For more information on merge tools see :hg:`help merge-tools`.
1426 For configuring merge tools see the ``[merge-tools]`` section.
1431 For configuring merge tools see the ``[merge-tools]`` section.
1427
1432
1428 ``mergemarkers``
1433 ``mergemarkers``
1429 Sets the merge conflict marker label styling. The ``detailed``
1434 Sets the merge conflict marker label styling. The ``detailed``
1430 style uses the ``mergemarkertemplate`` setting to style the labels.
1435 style uses the ``mergemarkertemplate`` setting to style the labels.
1431 The ``basic`` style just uses 'local' and 'other' as the marker label.
1436 The ``basic`` style just uses 'local' and 'other' as the marker label.
1432 One of ``basic`` or ``detailed``.
1437 One of ``basic`` or ``detailed``.
1433 Default is ``basic``.
1438 Default is ``basic``.
1434
1439
1435 ``mergemarkertemplate``
1440 ``mergemarkertemplate``
1436 The template used to print the commit description next to each conflict
1441 The template used to print the commit description next to each conflict
1437 marker during merge conflicts. See :hg:`help templates` for the template
1442 marker during merge conflicts. See :hg:`help templates` for the template
1438 format.
1443 format.
1439 Defaults to showing the hash, tags, branches, bookmarks, author, and
1444 Defaults to showing the hash, tags, branches, bookmarks, author, and
1440 the first line of the commit description.
1445 the first line of the commit description.
1441 If you use non-ASCII characters in names for tags, branches, bookmarks,
1446 If you use non-ASCII characters in names for tags, branches, bookmarks,
1442 authors, and/or commit descriptions, you must pay attention to encodings of
1447 authors, and/or commit descriptions, you must pay attention to encodings of
1443 managed files. At template expansion, non-ASCII characters use the encoding
1448 managed files. At template expansion, non-ASCII characters use the encoding
1444 specified by the ``--encoding`` global option, ``HGENCODING`` or other
1449 specified by the ``--encoding`` global option, ``HGENCODING`` or other
1445 environment variables that govern your locale. If the encoding of the merge
1450 environment variables that govern your locale. If the encoding of the merge
1446 markers is different from the encoding of the merged files,
1451 markers is different from the encoding of the merged files,
1447 serious problems may occur.
1452 serious problems may occur.
1448
1453
1449 ``portablefilenames``
1454 ``portablefilenames``
1450 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1455 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1451 Default is ``warn``.
1456 Default is ``warn``.
1452 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1457 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1453 platforms, if a file with a non-portable filename is added (e.g. a file
1458 platforms, if a file with a non-portable filename is added (e.g. a file
1454 with a name that can't be created on Windows because it contains reserved
1459 with a name that can't be created on Windows because it contains reserved
1455 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1460 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1456 collision with an existing file).
1461 collision with an existing file).
1457 If set to ``ignore`` (or ``false``), no warning is printed.
1462 If set to ``ignore`` (or ``false``), no warning is printed.
1458 If set to ``abort``, the command is aborted.
1463 If set to ``abort``, the command is aborted.
1459 On Windows, this configuration option is ignored and the command aborted.
1464 On Windows, this configuration option is ignored and the command aborted.
1460
1465
1461 ``quiet``
1466 ``quiet``
1462 Reduce the amount of output printed. True or False. Default is False.
1467 Reduce the amount of output printed. True or False. Default is False.
1463
1468
1464 ``remotecmd``
1469 ``remotecmd``
1465 remote command to use for clone/push/pull operations. Default is ``hg``.
1470 remote command to use for clone/push/pull operations. Default is ``hg``.
1466
1471
1467 ``report_untrusted``
1472 ``report_untrusted``
1468 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1473 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1469 trusted user or group. True or False. Default is True.
1474 trusted user or group. True or False. Default is True.
1470
1475
1471 ``slash``
1476 ``slash``
1472 Display paths using a slash (``/``) as the path separator. This
1477 Display paths using a slash (``/``) as the path separator. This
1473 only makes a difference on systems where the default path
1478 only makes a difference on systems where the default path
1474 separator is not the slash character (e.g. Windows uses the
1479 separator is not the slash character (e.g. Windows uses the
1475 backslash character (``\``)).
1480 backslash character (``\``)).
1476 Default is False.
1481 Default is False.
1477
1482
1478 ``statuscopies``
1483 ``statuscopies``
1479 Display copies in the status command.
1484 Display copies in the status command.
1480
1485
1481 ``ssh``
1486 ``ssh``
1482 command to use for SSH connections. Default is ``ssh``.
1487 command to use for SSH connections. Default is ``ssh``.
1483
1488
1484 ``strict``
1489 ``strict``
1485 Require exact command names, instead of allowing unambiguous
1490 Require exact command names, instead of allowing unambiguous
1486 abbreviations. True or False. Default is False.
1491 abbreviations. True or False. Default is False.
1487
1492
1488 ``style``
1493 ``style``
1489 Name of style to use for command output.
1494 Name of style to use for command output.
1490
1495
1491 ``timeout``
1496 ``timeout``
1492 The timeout used when a lock is held (in seconds), a negative value
1497 The timeout used when a lock is held (in seconds), a negative value
1493 means no timeout. Default is 600.
1498 means no timeout. Default is 600.
1494
1499
1495 ``traceback``
1500 ``traceback``
1496 Mercurial always prints a traceback when an unknown exception
1501 Mercurial always prints a traceback when an unknown exception
1497 occurs. Setting this to True will make Mercurial print a traceback
1502 occurs. Setting this to True will make Mercurial print a traceback
1498 on all exceptions, even those recognized by Mercurial (such as
1503 on all exceptions, even those recognized by Mercurial (such as
1499 IOError or MemoryError). Default is False.
1504 IOError or MemoryError). Default is False.
1500
1505
1501 ``username``
1506 ``username``
1502 The committer of a changeset created when running "commit".
1507 The committer of a changeset created when running "commit".
1503 Typically a person's name and email address, e.g. ``Fred Widget
1508 Typically a person's name and email address, e.g. ``Fred Widget
1504 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1509 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1505 the username in hgrc is empty, it has to be specified manually or
1510 the username in hgrc is empty, it has to be specified manually or
1506 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1511 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1507 ``username =`` in the system hgrc). Environment variables in the
1512 ``username =`` in the system hgrc). Environment variables in the
1508 username are expanded.
1513 username are expanded.
1509
1514
1510 ``verbose``
1515 ``verbose``
1511 Increase the amount of output printed. True or False. Default is False.
1516 Increase the amount of output printed. True or False. Default is False.
1512
1517
1513
1518
1514 ``web``
1519 ``web``
1515 -------
1520 -------
1516
1521
1517 Web interface configuration. The settings in this section apply to
1522 Web interface configuration. The settings in this section apply to
1518 both the builtin webserver (started by :hg:`serve`) and the script you
1523 both the builtin webserver (started by :hg:`serve`) and the script you
1519 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1524 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1520 and WSGI).
1525 and WSGI).
1521
1526
1522 The Mercurial webserver does no authentication (it does not prompt for
1527 The Mercurial webserver does no authentication (it does not prompt for
1523 usernames and passwords to validate *who* users are), but it does do
1528 usernames and passwords to validate *who* users are), but it does do
1524 authorization (it grants or denies access for *authenticated users*
1529 authorization (it grants or denies access for *authenticated users*
1525 based on settings in this section). You must either configure your
1530 based on settings in this section). You must either configure your
1526 webserver to do authentication for you, or disable the authorization
1531 webserver to do authentication for you, or disable the authorization
1527 checks.
1532 checks.
1528
1533
1529 For a quick setup in a trusted environment, e.g., a private LAN, where
1534 For a quick setup in a trusted environment, e.g., a private LAN, where
1530 you want it to accept pushes from anybody, you can use the following
1535 you want it to accept pushes from anybody, you can use the following
1531 command line::
1536 command line::
1532
1537
1533 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1538 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1534
1539
1535 Note that this will allow anybody to push anything to the server and
1540 Note that this will allow anybody to push anything to the server and
1536 that this should not be used for public servers.
1541 that this should not be used for public servers.
1537
1542
1538 The full set of options is:
1543 The full set of options is:
1539
1544
1540 ``accesslog``
1545 ``accesslog``
1541 Where to output the access log. Default is stdout.
1546 Where to output the access log. Default is stdout.
1542
1547
1543 ``address``
1548 ``address``
1544 Interface address to bind to. Default is all.
1549 Interface address to bind to. Default is all.
1545
1550
1546 ``allow_archive``
1551 ``allow_archive``
1547 List of archive format (bz2, gz, zip) allowed for downloading.
1552 List of archive format (bz2, gz, zip) allowed for downloading.
1548 Default is empty.
1553 Default is empty.
1549
1554
1550 ``allowbz2``
1555 ``allowbz2``
1551 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1556 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1552 revisions.
1557 revisions.
1553 Default is False.
1558 Default is False.
1554
1559
1555 ``allowgz``
1560 ``allowgz``
1556 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1561 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1557 revisions.
1562 revisions.
1558 Default is False.
1563 Default is False.
1559
1564
1560 ``allowpull``
1565 ``allowpull``
1561 Whether to allow pulling from the repository. Default is True.
1566 Whether to allow pulling from the repository. Default is True.
1562
1567
1563 ``allow_push``
1568 ``allow_push``
1564 Whether to allow pushing to the repository. If empty or not set,
1569 Whether to allow pushing to the repository. If empty or not set,
1565 push is not allowed. If the special value ``*``, any remote user can
1570 push is not allowed. If the special value ``*``, any remote user can
1566 push, including unauthenticated users. Otherwise, the remote user
1571 push, including unauthenticated users. Otherwise, the remote user
1567 must have been authenticated, and the authenticated user name must
1572 must have been authenticated, and the authenticated user name must
1568 be present in this list. The contents of the allow_push list are
1573 be present in this list. The contents of the allow_push list are
1569 examined after the deny_push list.
1574 examined after the deny_push list.
1570
1575
1571 ``allow_read``
1576 ``allow_read``
1572 If the user has not already been denied repository access due to
1577 If the user has not already been denied repository access due to
1573 the contents of deny_read, this list determines whether to grant
1578 the contents of deny_read, this list determines whether to grant
1574 repository access to the user. If this list is not empty, and the
1579 repository access to the user. If this list is not empty, and the
1575 user is unauthenticated or not present in the list, then access is
1580 user is unauthenticated or not present in the list, then access is
1576 denied for the user. If the list is empty or not set, then access
1581 denied for the user. If the list is empty or not set, then access
1577 is permitted to all users by default. Setting allow_read to the
1582 is permitted to all users by default. Setting allow_read to the
1578 special value ``*`` is equivalent to it not being set (i.e. access
1583 special value ``*`` is equivalent to it not being set (i.e. access
1579 is permitted to all users). The contents of the allow_read list are
1584 is permitted to all users). The contents of the allow_read list are
1580 examined after the deny_read list.
1585 examined after the deny_read list.
1581
1586
1582 ``allowzip``
1587 ``allowzip``
1583 (DEPRECATED) Whether to allow .zip downloading of repository
1588 (DEPRECATED) Whether to allow .zip downloading of repository
1584 revisions. Default is False. This feature creates temporary files.
1589 revisions. Default is False. This feature creates temporary files.
1585
1590
1586 ``archivesubrepos``
1591 ``archivesubrepos``
1587 Whether to recurse into subrepositories when archiving. Default is
1592 Whether to recurse into subrepositories when archiving. Default is
1588 False.
1593 False.
1589
1594
1590 ``baseurl``
1595 ``baseurl``
1591 Base URL to use when publishing URLs in other locations, so
1596 Base URL to use when publishing URLs in other locations, so
1592 third-party tools like email notification hooks can construct
1597 third-party tools like email notification hooks can construct
1593 URLs. Example: ``http://hgserver/repos/``.
1598 URLs. Example: ``http://hgserver/repos/``.
1594
1599
1595 ``cacerts``
1600 ``cacerts``
1596 Path to file containing a list of PEM encoded certificate
1601 Path to file containing a list of PEM encoded certificate
1597 authority certificates. Environment variables and ``~user``
1602 authority certificates. Environment variables and ``~user``
1598 constructs are expanded in the filename. If specified on the
1603 constructs are expanded in the filename. If specified on the
1599 client, then it will verify the identity of remote HTTPS servers
1604 client, then it will verify the identity of remote HTTPS servers
1600 with these certificates.
1605 with these certificates.
1601
1606
1602 This feature is only supported when using Python 2.6 or later. If you wish
1607 This feature is only supported when using Python 2.6 or later. If you wish
1603 to use it with earlier versions of Python, install the backported
1608 to use it with earlier versions of Python, install the backported
1604 version of the ssl library that is available from
1609 version of the ssl library that is available from
1605 ``http://pypi.python.org``.
1610 ``http://pypi.python.org``.
1606
1611
1607 To disable SSL verification temporarily, specify ``--insecure`` from
1612 To disable SSL verification temporarily, specify ``--insecure`` from
1608 command line.
1613 command line.
1609
1614
1610 You can use OpenSSL's CA certificate file if your platform has
1615 You can use OpenSSL's CA certificate file if your platform has
1611 one. On most Linux systems this will be
1616 one. On most Linux systems this will be
1612 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1617 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1613 generate this file manually. The form must be as follows::
1618 generate this file manually. The form must be as follows::
1614
1619
1615 -----BEGIN CERTIFICATE-----
1620 -----BEGIN CERTIFICATE-----
1616 ... (certificate in base64 PEM encoding) ...
1621 ... (certificate in base64 PEM encoding) ...
1617 -----END CERTIFICATE-----
1622 -----END CERTIFICATE-----
1618 -----BEGIN CERTIFICATE-----
1623 -----BEGIN CERTIFICATE-----
1619 ... (certificate in base64 PEM encoding) ...
1624 ... (certificate in base64 PEM encoding) ...
1620 -----END CERTIFICATE-----
1625 -----END CERTIFICATE-----
1621
1626
1622 ``cache``
1627 ``cache``
1623 Whether to support caching in hgweb. Defaults to True.
1628 Whether to support caching in hgweb. Defaults to True.
1624
1629
1625 ``collapse``
1630 ``collapse``
1626 With ``descend`` enabled, repositories in subdirectories are shown at
1631 With ``descend`` enabled, repositories in subdirectories are shown at
1627 a single level alongside repositories in the current path. With
1632 a single level alongside repositories in the current path. With
1628 ``collapse`` also enabled, repositories residing at a deeper level than
1633 ``collapse`` also enabled, repositories residing at a deeper level than
1629 the current path are grouped behind navigable directory entries that
1634 the current path are grouped behind navigable directory entries that
1630 lead to the locations of these repositories. In effect, this setting
1635 lead to the locations of these repositories. In effect, this setting
1631 collapses each collection of repositories found within a subdirectory
1636 collapses each collection of repositories found within a subdirectory
1632 into a single entry for that subdirectory. Default is False.
1637 into a single entry for that subdirectory. Default is False.
1633
1638
1634 ``comparisoncontext``
1639 ``comparisoncontext``
1635 Number of lines of context to show in side-by-side file comparison. If
1640 Number of lines of context to show in side-by-side file comparison. If
1636 negative or the value ``full``, whole files are shown. Default is 5.
1641 negative or the value ``full``, whole files are shown. Default is 5.
1637 This setting can be overridden by a ``context`` request parameter to the
1642 This setting can be overridden by a ``context`` request parameter to the
1638 ``comparison`` command, taking the same values.
1643 ``comparison`` command, taking the same values.
1639
1644
1640 ``contact``
1645 ``contact``
1641 Name or email address of the person in charge of the repository.
1646 Name or email address of the person in charge of the repository.
1642 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1647 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1643
1648
1644 ``deny_push``
1649 ``deny_push``
1645 Whether to deny pushing to the repository. If empty or not set,
1650 Whether to deny pushing to the repository. If empty or not set,
1646 push is not denied. If the special value ``*``, all remote users are
1651 push is not denied. If the special value ``*``, all remote users are
1647 denied push. Otherwise, unauthenticated users are all denied, and
1652 denied push. Otherwise, unauthenticated users are all denied, and
1648 any authenticated user name present in this list is also denied. The
1653 any authenticated user name present in this list is also denied. The
1649 contents of the deny_push list are examined before the allow_push list.
1654 contents of the deny_push list are examined before the allow_push list.
1650
1655
1651 ``deny_read``
1656 ``deny_read``
1652 Whether to deny reading/viewing of the repository. If this list is
1657 Whether to deny reading/viewing of the repository. If this list is
1653 not empty, unauthenticated users are all denied, and any
1658 not empty, unauthenticated users are all denied, and any
1654 authenticated user name present in this list is also denied access to
1659 authenticated user name present in this list is also denied access to
1655 the repository. If set to the special value ``*``, all remote users
1660 the repository. If set to the special value ``*``, all remote users
1656 are denied access (rarely needed ;). If deny_read is empty or not set,
1661 are denied access (rarely needed ;). If deny_read is empty or not set,
1657 the determination of repository access depends on the presence and
1662 the determination of repository access depends on the presence and
1658 content of the allow_read list (see description). If both
1663 content of the allow_read list (see description). If both
1659 deny_read and allow_read are empty or not set, then access is
1664 deny_read and allow_read are empty or not set, then access is
1660 permitted to all users by default. If the repository is being
1665 permitted to all users by default. If the repository is being
1661 served via hgwebdir, denied users will not be able to see it in
1666 served via hgwebdir, denied users will not be able to see it in
1662 the list of repositories. The contents of the deny_read list have
1667 the list of repositories. The contents of the deny_read list have
1663 priority over (are examined before) the contents of the allow_read
1668 priority over (are examined before) the contents of the allow_read
1664 list.
1669 list.
1665
1670
1666 ``descend``
1671 ``descend``
1667 hgwebdir indexes will not descend into subdirectories. Only repositories
1672 hgwebdir indexes will not descend into subdirectories. Only repositories
1668 directly in the current path will be shown (other repositories are still
1673 directly in the current path will be shown (other repositories are still
1669 available from the index corresponding to their containing path).
1674 available from the index corresponding to their containing path).
1670
1675
1671 ``description``
1676 ``description``
1672 Textual description of the repository's purpose or contents.
1677 Textual description of the repository's purpose or contents.
1673 Default is "unknown".
1678 Default is "unknown".
1674
1679
1675 ``encoding``
1680 ``encoding``
1676 Character encoding name. Default is the current locale charset.
1681 Character encoding name. Default is the current locale charset.
1677 Example: "UTF-8"
1682 Example: "UTF-8"
1678
1683
1679 ``errorlog``
1684 ``errorlog``
1680 Where to output the error log. Default is stderr.
1685 Where to output the error log. Default is stderr.
1681
1686
1682 ``guessmime``
1687 ``guessmime``
1683 Control MIME types for raw download of file content.
1688 Control MIME types for raw download of file content.
1684 Set to True to let hgweb guess the content type from the file
1689 Set to True to let hgweb guess the content type from the file
1685 extension. This will serve HTML files as ``text/html`` and might
1690 extension. This will serve HTML files as ``text/html`` and might
1686 allow cross-site scripting attacks when serving untrusted
1691 allow cross-site scripting attacks when serving untrusted
1687 repositories. Default is False.
1692 repositories. Default is False.
1688
1693
1689 ``hidden``
1694 ``hidden``
1690 Whether to hide the repository in the hgwebdir index.
1695 Whether to hide the repository in the hgwebdir index.
1691 Default is False.
1696 Default is False.
1692
1697
1693 ``ipv6``
1698 ``ipv6``
1694 Whether to use IPv6. Default is False.
1699 Whether to use IPv6. Default is False.
1695
1700
1696 ``logoimg``
1701 ``logoimg``
1697 File name of the logo image that some templates display on each page.
1702 File name of the logo image that some templates display on each page.
1698 The file name is relative to ``staticurl``. That is, the full path to
1703 The file name is relative to ``staticurl``. That is, the full path to
1699 the logo image is "staticurl/logoimg".
1704 the logo image is "staticurl/logoimg".
1700 If unset, ``hglogo.png`` will be used.
1705 If unset, ``hglogo.png`` will be used.
1701
1706
1702 ``logourl``
1707 ``logourl``
1703 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1708 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1704 will be used.
1709 will be used.
1705
1710
1706 ``maxchanges``
1711 ``maxchanges``
1707 Maximum number of changes to list on the changelog. Default is 10.
1712 Maximum number of changes to list on the changelog. Default is 10.
1708
1713
1709 ``maxfiles``
1714 ``maxfiles``
1710 Maximum number of files to list per changeset. Default is 10.
1715 Maximum number of files to list per changeset. Default is 10.
1711
1716
1712 ``maxshortchanges``
1717 ``maxshortchanges``
1713 Maximum number of changes to list on the shortlog, graph or filelog
1718 Maximum number of changes to list on the shortlog, graph or filelog
1714 pages. Default is 60.
1719 pages. Default is 60.
1715
1720
1716 ``name``
1721 ``name``
1717 Repository name to use in the web interface. Default is current
1722 Repository name to use in the web interface. Default is current
1718 working directory.
1723 working directory.
1719
1724
1720 ``port``
1725 ``port``
1721 Port to listen on. Default is 8000.
1726 Port to listen on. Default is 8000.
1722
1727
1723 ``prefix``
1728 ``prefix``
1724 Prefix path to serve from. Default is '' (server root).
1729 Prefix path to serve from. Default is '' (server root).
1725
1730
1726 ``push_ssl``
1731 ``push_ssl``
1727 Whether to require that inbound pushes be transported over SSL to
1732 Whether to require that inbound pushes be transported over SSL to
1728 prevent password sniffing. Default is True.
1733 prevent password sniffing. Default is True.
1729
1734
1730 ``staticurl``
1735 ``staticurl``
1731 Base URL to use for static files. If unset, static files (e.g. the
1736 Base URL to use for static files. If unset, static files (e.g. the
1732 hgicon.png favicon) will be served by the CGI script itself. Use
1737 hgicon.png favicon) will be served by the CGI script itself. Use
1733 this setting to serve them directly with the HTTP server.
1738 this setting to serve them directly with the HTTP server.
1734 Example: ``http://hgserver/static/``.
1739 Example: ``http://hgserver/static/``.
1735
1740
1736 ``stripes``
1741 ``stripes``
1737 How many lines a "zebra stripe" should span in multi-line output.
1742 How many lines a "zebra stripe" should span in multi-line output.
1738 Default is 1; set to 0 to disable.
1743 Default is 1; set to 0 to disable.
1739
1744
1740 ``style``
1745 ``style``
1741 Which template map style to use. The available options are the names of
1746 Which template map style to use. The available options are the names of
1742 subdirectories in the HTML templates path. Default is ``paper``.
1747 subdirectories in the HTML templates path. Default is ``paper``.
1743 Example: ``monoblue``
1748 Example: ``monoblue``
1744
1749
1745 ``templates``
1750 ``templates``
1746 Where to find the HTML templates. The default path to the HTML templates
1751 Where to find the HTML templates. The default path to the HTML templates
1747 can be obtained from ``hg debuginstall``.
1752 can be obtained from ``hg debuginstall``.
1748
1753
1749 ``websub``
1754 ``websub``
1750 ----------
1755 ----------
1751
1756
1752 Web substitution filter definition. You can use this section to
1757 Web substitution filter definition. You can use this section to
1753 define a set of regular expression substitution patterns which
1758 define a set of regular expression substitution patterns which
1754 let you automatically modify the hgweb server output.
1759 let you automatically modify the hgweb server output.
1755
1760
1756 The default hgweb templates only apply these substitution patterns
1761 The default hgweb templates only apply these substitution patterns
1757 on the revision description fields. You can apply them anywhere
1762 on the revision description fields. You can apply them anywhere
1758 you want when you create your own templates by adding calls to the
1763 you want when you create your own templates by adding calls to the
1759 "websub" filter (usually after calling the "escape" filter).
1764 "websub" filter (usually after calling the "escape" filter).
1760
1765
1761 This can be used, for example, to convert issue references to links
1766 This can be used, for example, to convert issue references to links
1762 to your issue tracker, or to convert "markdown-like" syntax into
1767 to your issue tracker, or to convert "markdown-like" syntax into
1763 HTML (see the examples below).
1768 HTML (see the examples below).
1764
1769
1765 Each entry in this section names a substitution filter.
1770 Each entry in this section names a substitution filter.
1766 The value of each entry defines the substitution expression itself.
1771 The value of each entry defines the substitution expression itself.
1767 The websub expressions follow the old interhg extension syntax,
1772 The websub expressions follow the old interhg extension syntax,
1768 which in turn imitates the Unix sed replacement syntax::
1773 which in turn imitates the Unix sed replacement syntax::
1769
1774
1770 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1775 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1771
1776
1772 You can use any separator other than "/". The final "i" is optional
1777 You can use any separator other than "/". The final "i" is optional
1773 and indicates that the search must be case insensitive.
1778 and indicates that the search must be case insensitive.
1774
1779
1775 Examples::
1780 Examples::
1776
1781
1777 [websub]
1782 [websub]
1778 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1783 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1779 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1784 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1780 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1785 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1781
1786
1782 ``worker``
1787 ``worker``
1783 ----------
1788 ----------
1784
1789
1785 Parallel master/worker configuration. We currently perform working
1790 Parallel master/worker configuration. We currently perform working
1786 directory updates in parallel on Unix-like systems, which greatly
1791 directory updates in parallel on Unix-like systems, which greatly
1787 helps performance.
1792 helps performance.
1788
1793
1789 ``numcpus``
1794 ``numcpus``
1790 Number of CPUs to use for parallel operations. Default is 4 or the
1795 Number of CPUs to use for parallel operations. Default is 4 or the
1791 number of CPUs on the system, whichever is larger. A zero or
1796 number of CPUs on the system, whichever is larger. A zero or
1792 negative value is treated as ``use the default``.
1797 negative value is treated as ``use the default``.
@@ -1,2553 +1,2553
1 # patch.py - patch file parsing routines
1 # patch.py - patch file parsing routines
2 #
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
4 # Copyright 2007 Chris Mason <chris.mason@oracle.com>
4 # Copyright 2007 Chris Mason <chris.mason@oracle.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import collections
9 import collections
10 import cStringIO, email, os, errno, re, posixpath, copy
10 import cStringIO, email, os, errno, re, posixpath, copy
11 import tempfile, zlib, shutil
11 import tempfile, zlib, shutil
12 # On python2.4 you have to import these by name or they fail to
12 # On python2.4 you have to import these by name or they fail to
13 # load. This was not a problem on Python 2.7.
13 # load. This was not a problem on Python 2.7.
14 import email.Generator
14 import email.Generator
15 import email.Parser
15 import email.Parser
16
16
17 from i18n import _
17 from i18n import _
18 from node import hex, short
18 from node import hex, short
19 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
19 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
20 import pathutil
20 import pathutil
21
21
22 gitre = re.compile('diff --git a/(.*) b/(.*)')
22 gitre = re.compile('diff --git a/(.*) b/(.*)')
23 tabsplitter = re.compile(r'(\t+|[^\t]+)')
23 tabsplitter = re.compile(r'(\t+|[^\t]+)')
24
24
25 class PatchError(Exception):
25 class PatchError(Exception):
26 pass
26 pass
27
27
28
28
29 # public functions
29 # public functions
30
30
31 def split(stream):
31 def split(stream):
32 '''return an iterator of individual patches from a stream'''
32 '''return an iterator of individual patches from a stream'''
33 def isheader(line, inheader):
33 def isheader(line, inheader):
34 if inheader and line[0] in (' ', '\t'):
34 if inheader and line[0] in (' ', '\t'):
35 # continuation
35 # continuation
36 return True
36 return True
37 if line[0] in (' ', '-', '+'):
37 if line[0] in (' ', '-', '+'):
38 # diff line - don't check for header pattern in there
38 # diff line - don't check for header pattern in there
39 return False
39 return False
40 l = line.split(': ', 1)
40 l = line.split(': ', 1)
41 return len(l) == 2 and ' ' not in l[0]
41 return len(l) == 2 and ' ' not in l[0]
42
42
43 def chunk(lines):
43 def chunk(lines):
44 return cStringIO.StringIO(''.join(lines))
44 return cStringIO.StringIO(''.join(lines))
45
45
46 def hgsplit(stream, cur):
46 def hgsplit(stream, cur):
47 inheader = True
47 inheader = True
48
48
49 for line in stream:
49 for line in stream:
50 if not line.strip():
50 if not line.strip():
51 inheader = False
51 inheader = False
52 if not inheader and line.startswith('# HG changeset patch'):
52 if not inheader and line.startswith('# HG changeset patch'):
53 yield chunk(cur)
53 yield chunk(cur)
54 cur = []
54 cur = []
55 inheader = True
55 inheader = True
56
56
57 cur.append(line)
57 cur.append(line)
58
58
59 if cur:
59 if cur:
60 yield chunk(cur)
60 yield chunk(cur)
61
61
62 def mboxsplit(stream, cur):
62 def mboxsplit(stream, cur):
63 for line in stream:
63 for line in stream:
64 if line.startswith('From '):
64 if line.startswith('From '):
65 for c in split(chunk(cur[1:])):
65 for c in split(chunk(cur[1:])):
66 yield c
66 yield c
67 cur = []
67 cur = []
68
68
69 cur.append(line)
69 cur.append(line)
70
70
71 if cur:
71 if cur:
72 for c in split(chunk(cur[1:])):
72 for c in split(chunk(cur[1:])):
73 yield c
73 yield c
74
74
75 def mimesplit(stream, cur):
75 def mimesplit(stream, cur):
76 def msgfp(m):
76 def msgfp(m):
77 fp = cStringIO.StringIO()
77 fp = cStringIO.StringIO()
78 g = email.Generator.Generator(fp, mangle_from_=False)
78 g = email.Generator.Generator(fp, mangle_from_=False)
79 g.flatten(m)
79 g.flatten(m)
80 fp.seek(0)
80 fp.seek(0)
81 return fp
81 return fp
82
82
83 for line in stream:
83 for line in stream:
84 cur.append(line)
84 cur.append(line)
85 c = chunk(cur)
85 c = chunk(cur)
86
86
87 m = email.Parser.Parser().parse(c)
87 m = email.Parser.Parser().parse(c)
88 if not m.is_multipart():
88 if not m.is_multipart():
89 yield msgfp(m)
89 yield msgfp(m)
90 else:
90 else:
91 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
91 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
92 for part in m.walk():
92 for part in m.walk():
93 ct = part.get_content_type()
93 ct = part.get_content_type()
94 if ct not in ok_types:
94 if ct not in ok_types:
95 continue
95 continue
96 yield msgfp(part)
96 yield msgfp(part)
97
97
98 def headersplit(stream, cur):
98 def headersplit(stream, cur):
99 inheader = False
99 inheader = False
100
100
101 for line in stream:
101 for line in stream:
102 if not inheader and isheader(line, inheader):
102 if not inheader and isheader(line, inheader):
103 yield chunk(cur)
103 yield chunk(cur)
104 cur = []
104 cur = []
105 inheader = True
105 inheader = True
106 if inheader and not isheader(line, inheader):
106 if inheader and not isheader(line, inheader):
107 inheader = False
107 inheader = False
108
108
109 cur.append(line)
109 cur.append(line)
110
110
111 if cur:
111 if cur:
112 yield chunk(cur)
112 yield chunk(cur)
113
113
114 def remainder(cur):
114 def remainder(cur):
115 yield chunk(cur)
115 yield chunk(cur)
116
116
117 class fiter(object):
117 class fiter(object):
118 def __init__(self, fp):
118 def __init__(self, fp):
119 self.fp = fp
119 self.fp = fp
120
120
121 def __iter__(self):
121 def __iter__(self):
122 return self
122 return self
123
123
124 def next(self):
124 def next(self):
125 l = self.fp.readline()
125 l = self.fp.readline()
126 if not l:
126 if not l:
127 raise StopIteration
127 raise StopIteration
128 return l
128 return l
129
129
130 inheader = False
130 inheader = False
131 cur = []
131 cur = []
132
132
133 mimeheaders = ['content-type']
133 mimeheaders = ['content-type']
134
134
135 if not util.safehasattr(stream, 'next'):
135 if not util.safehasattr(stream, 'next'):
136 # http responses, for example, have readline but not next
136 # http responses, for example, have readline but not next
137 stream = fiter(stream)
137 stream = fiter(stream)
138
138
139 for line in stream:
139 for line in stream:
140 cur.append(line)
140 cur.append(line)
141 if line.startswith('# HG changeset patch'):
141 if line.startswith('# HG changeset patch'):
142 return hgsplit(stream, cur)
142 return hgsplit(stream, cur)
143 elif line.startswith('From '):
143 elif line.startswith('From '):
144 return mboxsplit(stream, cur)
144 return mboxsplit(stream, cur)
145 elif isheader(line, inheader):
145 elif isheader(line, inheader):
146 inheader = True
146 inheader = True
147 if line.split(':', 1)[0].lower() in mimeheaders:
147 if line.split(':', 1)[0].lower() in mimeheaders:
148 # let email parser handle this
148 # let email parser handle this
149 return mimesplit(stream, cur)
149 return mimesplit(stream, cur)
150 elif line.startswith('--- ') and inheader:
150 elif line.startswith('--- ') and inheader:
151 # No evil headers seen by diff start, split by hand
151 # No evil headers seen by diff start, split by hand
152 return headersplit(stream, cur)
152 return headersplit(stream, cur)
153 # Not enough info, keep reading
153 # Not enough info, keep reading
154
154
155 # if we are here, we have a very plain patch
155 # if we are here, we have a very plain patch
156 return remainder(cur)
156 return remainder(cur)
157
157
158 def extract(ui, fileobj):
158 def extract(ui, fileobj):
159 '''extract patch from data read from fileobj.
159 '''extract patch from data read from fileobj.
160
160
161 patch can be a normal patch or contained in an email message.
161 patch can be a normal patch or contained in an email message.
162
162
163 return tuple (filename, message, user, date, branch, node, p1, p2).
163 return tuple (filename, message, user, date, branch, node, p1, p2).
164 Any item in the returned tuple can be None. If filename is None,
164 Any item in the returned tuple can be None. If filename is None,
165 fileobj did not contain a patch. Caller must unlink filename when done.'''
165 fileobj did not contain a patch. Caller must unlink filename when done.'''
166
166
167 # attempt to detect the start of a patch
167 # attempt to detect the start of a patch
168 # (this heuristic is borrowed from quilt)
168 # (this heuristic is borrowed from quilt)
169 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |'
169 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |'
170 r'retrieving revision [0-9]+(\.[0-9]+)*$|'
170 r'retrieving revision [0-9]+(\.[0-9]+)*$|'
171 r'---[ \t].*?^\+\+\+[ \t]|'
171 r'---[ \t].*?^\+\+\+[ \t]|'
172 r'\*\*\*[ \t].*?^---[ \t])', re.MULTILINE|re.DOTALL)
172 r'\*\*\*[ \t].*?^---[ \t])', re.MULTILINE|re.DOTALL)
173
173
174 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
174 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
175 tmpfp = os.fdopen(fd, 'w')
175 tmpfp = os.fdopen(fd, 'w')
176 try:
176 try:
177 msg = email.Parser.Parser().parse(fileobj)
177 msg = email.Parser.Parser().parse(fileobj)
178
178
179 subject = msg['Subject']
179 subject = msg['Subject']
180 user = msg['From']
180 user = msg['From']
181 if not subject and not user:
181 if not subject and not user:
182 # Not an email, restore parsed headers if any
182 # Not an email, restore parsed headers if any
183 subject = '\n'.join(': '.join(h) for h in msg.items()) + '\n'
183 subject = '\n'.join(': '.join(h) for h in msg.items()) + '\n'
184
184
185 # should try to parse msg['Date']
185 # should try to parse msg['Date']
186 date = None
186 date = None
187 nodeid = None
187 nodeid = None
188 branch = None
188 branch = None
189 parents = []
189 parents = []
190
190
191 if subject:
191 if subject:
192 if subject.startswith('[PATCH'):
192 if subject.startswith('[PATCH'):
193 pend = subject.find(']')
193 pend = subject.find(']')
194 if pend >= 0:
194 if pend >= 0:
195 subject = subject[pend + 1:].lstrip()
195 subject = subject[pend + 1:].lstrip()
196 subject = re.sub(r'\n[ \t]+', ' ', subject)
196 subject = re.sub(r'\n[ \t]+', ' ', subject)
197 ui.debug('Subject: %s\n' % subject)
197 ui.debug('Subject: %s\n' % subject)
198 if user:
198 if user:
199 ui.debug('From: %s\n' % user)
199 ui.debug('From: %s\n' % user)
200 diffs_seen = 0
200 diffs_seen = 0
201 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
201 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
202 message = ''
202 message = ''
203 for part in msg.walk():
203 for part in msg.walk():
204 content_type = part.get_content_type()
204 content_type = part.get_content_type()
205 ui.debug('Content-Type: %s\n' % content_type)
205 ui.debug('Content-Type: %s\n' % content_type)
206 if content_type not in ok_types:
206 if content_type not in ok_types:
207 continue
207 continue
208 payload = part.get_payload(decode=True)
208 payload = part.get_payload(decode=True)
209 m = diffre.search(payload)
209 m = diffre.search(payload)
210 if m:
210 if m:
211 hgpatch = False
211 hgpatch = False
212 hgpatchheader = False
212 hgpatchheader = False
213 ignoretext = False
213 ignoretext = False
214
214
215 ui.debug('found patch at byte %d\n' % m.start(0))
215 ui.debug('found patch at byte %d\n' % m.start(0))
216 diffs_seen += 1
216 diffs_seen += 1
217 cfp = cStringIO.StringIO()
217 cfp = cStringIO.StringIO()
218 for line in payload[:m.start(0)].splitlines():
218 for line in payload[:m.start(0)].splitlines():
219 if line.startswith('# HG changeset patch') and not hgpatch:
219 if line.startswith('# HG changeset patch') and not hgpatch:
220 ui.debug('patch generated by hg export\n')
220 ui.debug('patch generated by hg export\n')
221 hgpatch = True
221 hgpatch = True
222 hgpatchheader = True
222 hgpatchheader = True
223 # drop earlier commit message content
223 # drop earlier commit message content
224 cfp.seek(0)
224 cfp.seek(0)
225 cfp.truncate()
225 cfp.truncate()
226 subject = None
226 subject = None
227 elif hgpatchheader:
227 elif hgpatchheader:
228 if line.startswith('# User '):
228 if line.startswith('# User '):
229 user = line[7:]
229 user = line[7:]
230 ui.debug('From: %s\n' % user)
230 ui.debug('From: %s\n' % user)
231 elif line.startswith("# Date "):
231 elif line.startswith("# Date "):
232 date = line[7:]
232 date = line[7:]
233 elif line.startswith("# Branch "):
233 elif line.startswith("# Branch "):
234 branch = line[9:]
234 branch = line[9:]
235 elif line.startswith("# Node ID "):
235 elif line.startswith("# Node ID "):
236 nodeid = line[10:]
236 nodeid = line[10:]
237 elif line.startswith("# Parent "):
237 elif line.startswith("# Parent "):
238 parents.append(line[9:].lstrip())
238 parents.append(line[9:].lstrip())
239 elif not line.startswith("# "):
239 elif not line.startswith("# "):
240 hgpatchheader = False
240 hgpatchheader = False
241 elif line == '---':
241 elif line == '---':
242 ignoretext = True
242 ignoretext = True
243 if not hgpatchheader and not ignoretext:
243 if not hgpatchheader and not ignoretext:
244 cfp.write(line)
244 cfp.write(line)
245 cfp.write('\n')
245 cfp.write('\n')
246 message = cfp.getvalue()
246 message = cfp.getvalue()
247 if tmpfp:
247 if tmpfp:
248 tmpfp.write(payload)
248 tmpfp.write(payload)
249 if not payload.endswith('\n'):
249 if not payload.endswith('\n'):
250 tmpfp.write('\n')
250 tmpfp.write('\n')
251 elif not diffs_seen and message and content_type == 'text/plain':
251 elif not diffs_seen and message and content_type == 'text/plain':
252 message += '\n' + payload
252 message += '\n' + payload
253 except: # re-raises
253 except: # re-raises
254 tmpfp.close()
254 tmpfp.close()
255 os.unlink(tmpname)
255 os.unlink(tmpname)
256 raise
256 raise
257
257
258 if subject and not message.startswith(subject):
258 if subject and not message.startswith(subject):
259 message = '%s\n%s' % (subject, message)
259 message = '%s\n%s' % (subject, message)
260 tmpfp.close()
260 tmpfp.close()
261 if not diffs_seen:
261 if not diffs_seen:
262 os.unlink(tmpname)
262 os.unlink(tmpname)
263 return None, message, user, date, branch, None, None, None
263 return None, message, user, date, branch, None, None, None
264
264
265 if parents:
265 if parents:
266 p1 = parents.pop(0)
266 p1 = parents.pop(0)
267 else:
267 else:
268 p1 = None
268 p1 = None
269
269
270 if parents:
270 if parents:
271 p2 = parents.pop(0)
271 p2 = parents.pop(0)
272 else:
272 else:
273 p2 = None
273 p2 = None
274
274
275 return tmpname, message, user, date, branch, nodeid, p1, p2
275 return tmpname, message, user, date, branch, nodeid, p1, p2
276
276
277 class patchmeta(object):
277 class patchmeta(object):
278 """Patched file metadata
278 """Patched file metadata
279
279
280 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY
280 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY
281 or COPY. 'path' is patched file path. 'oldpath' is set to the
281 or COPY. 'path' is patched file path. 'oldpath' is set to the
282 origin file when 'op' is either COPY or RENAME, None otherwise. If
282 origin file when 'op' is either COPY or RENAME, None otherwise. If
283 file mode is changed, 'mode' is a tuple (islink, isexec) where
283 file mode is changed, 'mode' is a tuple (islink, isexec) where
284 'islink' is True if the file is a symlink and 'isexec' is True if
284 'islink' is True if the file is a symlink and 'isexec' is True if
285 the file is executable. Otherwise, 'mode' is None.
285 the file is executable. Otherwise, 'mode' is None.
286 """
286 """
287 def __init__(self, path):
287 def __init__(self, path):
288 self.path = path
288 self.path = path
289 self.oldpath = None
289 self.oldpath = None
290 self.mode = None
290 self.mode = None
291 self.op = 'MODIFY'
291 self.op = 'MODIFY'
292 self.binary = False
292 self.binary = False
293
293
294 def setmode(self, mode):
294 def setmode(self, mode):
295 islink = mode & 020000
295 islink = mode & 020000
296 isexec = mode & 0100
296 isexec = mode & 0100
297 self.mode = (islink, isexec)
297 self.mode = (islink, isexec)
298
298
299 def copy(self):
299 def copy(self):
300 other = patchmeta(self.path)
300 other = patchmeta(self.path)
301 other.oldpath = self.oldpath
301 other.oldpath = self.oldpath
302 other.mode = self.mode
302 other.mode = self.mode
303 other.op = self.op
303 other.op = self.op
304 other.binary = self.binary
304 other.binary = self.binary
305 return other
305 return other
306
306
307 def _ispatchinga(self, afile):
307 def _ispatchinga(self, afile):
308 if afile == '/dev/null':
308 if afile == '/dev/null':
309 return self.op == 'ADD'
309 return self.op == 'ADD'
310 return afile == 'a/' + (self.oldpath or self.path)
310 return afile == 'a/' + (self.oldpath or self.path)
311
311
312 def _ispatchingb(self, bfile):
312 def _ispatchingb(self, bfile):
313 if bfile == '/dev/null':
313 if bfile == '/dev/null':
314 return self.op == 'DELETE'
314 return self.op == 'DELETE'
315 return bfile == 'b/' + self.path
315 return bfile == 'b/' + self.path
316
316
317 def ispatching(self, afile, bfile):
317 def ispatching(self, afile, bfile):
318 return self._ispatchinga(afile) and self._ispatchingb(bfile)
318 return self._ispatchinga(afile) and self._ispatchingb(bfile)
319
319
320 def __repr__(self):
320 def __repr__(self):
321 return "<patchmeta %s %r>" % (self.op, self.path)
321 return "<patchmeta %s %r>" % (self.op, self.path)
322
322
323 def readgitpatch(lr):
323 def readgitpatch(lr):
324 """extract git-style metadata about patches from <patchname>"""
324 """extract git-style metadata about patches from <patchname>"""
325
325
326 # Filter patch for git information
326 # Filter patch for git information
327 gp = None
327 gp = None
328 gitpatches = []
328 gitpatches = []
329 for line in lr:
329 for line in lr:
330 line = line.rstrip(' \r\n')
330 line = line.rstrip(' \r\n')
331 if line.startswith('diff --git a/'):
331 if line.startswith('diff --git a/'):
332 m = gitre.match(line)
332 m = gitre.match(line)
333 if m:
333 if m:
334 if gp:
334 if gp:
335 gitpatches.append(gp)
335 gitpatches.append(gp)
336 dst = m.group(2)
336 dst = m.group(2)
337 gp = patchmeta(dst)
337 gp = patchmeta(dst)
338 elif gp:
338 elif gp:
339 if line.startswith('--- '):
339 if line.startswith('--- '):
340 gitpatches.append(gp)
340 gitpatches.append(gp)
341 gp = None
341 gp = None
342 continue
342 continue
343 if line.startswith('rename from '):
343 if line.startswith('rename from '):
344 gp.op = 'RENAME'
344 gp.op = 'RENAME'
345 gp.oldpath = line[12:]
345 gp.oldpath = line[12:]
346 elif line.startswith('rename to '):
346 elif line.startswith('rename to '):
347 gp.path = line[10:]
347 gp.path = line[10:]
348 elif line.startswith('copy from '):
348 elif line.startswith('copy from '):
349 gp.op = 'COPY'
349 gp.op = 'COPY'
350 gp.oldpath = line[10:]
350 gp.oldpath = line[10:]
351 elif line.startswith('copy to '):
351 elif line.startswith('copy to '):
352 gp.path = line[8:]
352 gp.path = line[8:]
353 elif line.startswith('deleted file'):
353 elif line.startswith('deleted file'):
354 gp.op = 'DELETE'
354 gp.op = 'DELETE'
355 elif line.startswith('new file mode '):
355 elif line.startswith('new file mode '):
356 gp.op = 'ADD'
356 gp.op = 'ADD'
357 gp.setmode(int(line[-6:], 8))
357 gp.setmode(int(line[-6:], 8))
358 elif line.startswith('new mode '):
358 elif line.startswith('new mode '):
359 gp.setmode(int(line[-6:], 8))
359 gp.setmode(int(line[-6:], 8))
360 elif line.startswith('GIT binary patch'):
360 elif line.startswith('GIT binary patch'):
361 gp.binary = True
361 gp.binary = True
362 if gp:
362 if gp:
363 gitpatches.append(gp)
363 gitpatches.append(gp)
364
364
365 return gitpatches
365 return gitpatches
366
366
367 class linereader(object):
367 class linereader(object):
368 # simple class to allow pushing lines back into the input stream
368 # simple class to allow pushing lines back into the input stream
369 def __init__(self, fp):
369 def __init__(self, fp):
370 self.fp = fp
370 self.fp = fp
371 self.buf = []
371 self.buf = []
372
372
373 def push(self, line):
373 def push(self, line):
374 if line is not None:
374 if line is not None:
375 self.buf.append(line)
375 self.buf.append(line)
376
376
377 def readline(self):
377 def readline(self):
378 if self.buf:
378 if self.buf:
379 l = self.buf[0]
379 l = self.buf[0]
380 del self.buf[0]
380 del self.buf[0]
381 return l
381 return l
382 return self.fp.readline()
382 return self.fp.readline()
383
383
384 def __iter__(self):
384 def __iter__(self):
385 while True:
385 while True:
386 l = self.readline()
386 l = self.readline()
387 if not l:
387 if not l:
388 break
388 break
389 yield l
389 yield l
390
390
391 class abstractbackend(object):
391 class abstractbackend(object):
392 def __init__(self, ui):
392 def __init__(self, ui):
393 self.ui = ui
393 self.ui = ui
394
394
395 def getfile(self, fname):
395 def getfile(self, fname):
396 """Return target file data and flags as a (data, (islink,
396 """Return target file data and flags as a (data, (islink,
397 isexec)) tuple. Data is None if file is missing/deleted.
397 isexec)) tuple. Data is None if file is missing/deleted.
398 """
398 """
399 raise NotImplementedError
399 raise NotImplementedError
400
400
401 def setfile(self, fname, data, mode, copysource):
401 def setfile(self, fname, data, mode, copysource):
402 """Write data to target file fname and set its mode. mode is a
402 """Write data to target file fname and set its mode. mode is a
403 (islink, isexec) tuple. If data is None, the file content should
403 (islink, isexec) tuple. If data is None, the file content should
404 be left unchanged. If the file is modified after being copied,
404 be left unchanged. If the file is modified after being copied,
405 copysource is set to the original file name.
405 copysource is set to the original file name.
406 """
406 """
407 raise NotImplementedError
407 raise NotImplementedError
408
408
409 def unlink(self, fname):
409 def unlink(self, fname):
410 """Unlink target file."""
410 """Unlink target file."""
411 raise NotImplementedError
411 raise NotImplementedError
412
412
413 def writerej(self, fname, failed, total, lines):
413 def writerej(self, fname, failed, total, lines):
414 """Write rejected lines for fname. total is the number of hunks
414 """Write rejected lines for fname. total is the number of hunks
415 which failed to apply and total the total number of hunks for this
415 which failed to apply and total the total number of hunks for this
416 files.
416 files.
417 """
417 """
418 pass
418 pass
419
419
420 def exists(self, fname):
420 def exists(self, fname):
421 raise NotImplementedError
421 raise NotImplementedError
422
422
423 class fsbackend(abstractbackend):
423 class fsbackend(abstractbackend):
424 def __init__(self, ui, basedir):
424 def __init__(self, ui, basedir):
425 super(fsbackend, self).__init__(ui)
425 super(fsbackend, self).__init__(ui)
426 self.opener = scmutil.opener(basedir)
426 self.opener = scmutil.opener(basedir)
427
427
428 def _join(self, f):
428 def _join(self, f):
429 return os.path.join(self.opener.base, f)
429 return os.path.join(self.opener.base, f)
430
430
431 def getfile(self, fname):
431 def getfile(self, fname):
432 if self.opener.islink(fname):
432 if self.opener.islink(fname):
433 return (self.opener.readlink(fname), (True, False))
433 return (self.opener.readlink(fname), (True, False))
434
434
435 isexec = False
435 isexec = False
436 try:
436 try:
437 isexec = self.opener.lstat(fname).st_mode & 0100 != 0
437 isexec = self.opener.lstat(fname).st_mode & 0100 != 0
438 except OSError, e:
438 except OSError, e:
439 if e.errno != errno.ENOENT:
439 if e.errno != errno.ENOENT:
440 raise
440 raise
441 try:
441 try:
442 return (self.opener.read(fname), (False, isexec))
442 return (self.opener.read(fname), (False, isexec))
443 except IOError, e:
443 except IOError, e:
444 if e.errno != errno.ENOENT:
444 if e.errno != errno.ENOENT:
445 raise
445 raise
446 return None, None
446 return None, None
447
447
448 def setfile(self, fname, data, mode, copysource):
448 def setfile(self, fname, data, mode, copysource):
449 islink, isexec = mode
449 islink, isexec = mode
450 if data is None:
450 if data is None:
451 self.opener.setflags(fname, islink, isexec)
451 self.opener.setflags(fname, islink, isexec)
452 return
452 return
453 if islink:
453 if islink:
454 self.opener.symlink(data, fname)
454 self.opener.symlink(data, fname)
455 else:
455 else:
456 self.opener.write(fname, data)
456 self.opener.write(fname, data)
457 if isexec:
457 if isexec:
458 self.opener.setflags(fname, False, True)
458 self.opener.setflags(fname, False, True)
459
459
460 def unlink(self, fname):
460 def unlink(self, fname):
461 self.opener.unlinkpath(fname, ignoremissing=True)
461 self.opener.unlinkpath(fname, ignoremissing=True)
462
462
463 def writerej(self, fname, failed, total, lines):
463 def writerej(self, fname, failed, total, lines):
464 fname = fname + ".rej"
464 fname = fname + ".rej"
465 self.ui.warn(
465 self.ui.warn(
466 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
466 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
467 (failed, total, fname))
467 (failed, total, fname))
468 fp = self.opener(fname, 'w')
468 fp = self.opener(fname, 'w')
469 fp.writelines(lines)
469 fp.writelines(lines)
470 fp.close()
470 fp.close()
471
471
472 def exists(self, fname):
472 def exists(self, fname):
473 return self.opener.lexists(fname)
473 return self.opener.lexists(fname)
474
474
475 class workingbackend(fsbackend):
475 class workingbackend(fsbackend):
476 def __init__(self, ui, repo, similarity):
476 def __init__(self, ui, repo, similarity):
477 super(workingbackend, self).__init__(ui, repo.root)
477 super(workingbackend, self).__init__(ui, repo.root)
478 self.repo = repo
478 self.repo = repo
479 self.similarity = similarity
479 self.similarity = similarity
480 self.removed = set()
480 self.removed = set()
481 self.changed = set()
481 self.changed = set()
482 self.copied = []
482 self.copied = []
483
483
484 def _checkknown(self, fname):
484 def _checkknown(self, fname):
485 if self.repo.dirstate[fname] == '?' and self.exists(fname):
485 if self.repo.dirstate[fname] == '?' and self.exists(fname):
486 raise PatchError(_('cannot patch %s: file is not tracked') % fname)
486 raise PatchError(_('cannot patch %s: file is not tracked') % fname)
487
487
488 def setfile(self, fname, data, mode, copysource):
488 def setfile(self, fname, data, mode, copysource):
489 self._checkknown(fname)
489 self._checkknown(fname)
490 super(workingbackend, self).setfile(fname, data, mode, copysource)
490 super(workingbackend, self).setfile(fname, data, mode, copysource)
491 if copysource is not None:
491 if copysource is not None:
492 self.copied.append((copysource, fname))
492 self.copied.append((copysource, fname))
493 self.changed.add(fname)
493 self.changed.add(fname)
494
494
495 def unlink(self, fname):
495 def unlink(self, fname):
496 self._checkknown(fname)
496 self._checkknown(fname)
497 super(workingbackend, self).unlink(fname)
497 super(workingbackend, self).unlink(fname)
498 self.removed.add(fname)
498 self.removed.add(fname)
499 self.changed.add(fname)
499 self.changed.add(fname)
500
500
501 def close(self):
501 def close(self):
502 wctx = self.repo[None]
502 wctx = self.repo[None]
503 changed = set(self.changed)
503 changed = set(self.changed)
504 for src, dst in self.copied:
504 for src, dst in self.copied:
505 scmutil.dirstatecopy(self.ui, self.repo, wctx, src, dst)
505 scmutil.dirstatecopy(self.ui, self.repo, wctx, src, dst)
506 if self.removed:
506 if self.removed:
507 wctx.forget(sorted(self.removed))
507 wctx.forget(sorted(self.removed))
508 for f in self.removed:
508 for f in self.removed:
509 if f not in self.repo.dirstate:
509 if f not in self.repo.dirstate:
510 # File was deleted and no longer belongs to the
510 # File was deleted and no longer belongs to the
511 # dirstate, it was probably marked added then
511 # dirstate, it was probably marked added then
512 # deleted, and should not be considered by
512 # deleted, and should not be considered by
513 # marktouched().
513 # marktouched().
514 changed.discard(f)
514 changed.discard(f)
515 if changed:
515 if changed:
516 scmutil.marktouched(self.repo, changed, self.similarity)
516 scmutil.marktouched(self.repo, changed, self.similarity)
517 return sorted(self.changed)
517 return sorted(self.changed)
518
518
519 class filestore(object):
519 class filestore(object):
520 def __init__(self, maxsize=None):
520 def __init__(self, maxsize=None):
521 self.opener = None
521 self.opener = None
522 self.files = {}
522 self.files = {}
523 self.created = 0
523 self.created = 0
524 self.maxsize = maxsize
524 self.maxsize = maxsize
525 if self.maxsize is None:
525 if self.maxsize is None:
526 self.maxsize = 4*(2**20)
526 self.maxsize = 4*(2**20)
527 self.size = 0
527 self.size = 0
528 self.data = {}
528 self.data = {}
529
529
530 def setfile(self, fname, data, mode, copied=None):
530 def setfile(self, fname, data, mode, copied=None):
531 if self.maxsize < 0 or (len(data) + self.size) <= self.maxsize:
531 if self.maxsize < 0 or (len(data) + self.size) <= self.maxsize:
532 self.data[fname] = (data, mode, copied)
532 self.data[fname] = (data, mode, copied)
533 self.size += len(data)
533 self.size += len(data)
534 else:
534 else:
535 if self.opener is None:
535 if self.opener is None:
536 root = tempfile.mkdtemp(prefix='hg-patch-')
536 root = tempfile.mkdtemp(prefix='hg-patch-')
537 self.opener = scmutil.opener(root)
537 self.opener = scmutil.opener(root)
538 # Avoid filename issues with these simple names
538 # Avoid filename issues with these simple names
539 fn = str(self.created)
539 fn = str(self.created)
540 self.opener.write(fn, data)
540 self.opener.write(fn, data)
541 self.created += 1
541 self.created += 1
542 self.files[fname] = (fn, mode, copied)
542 self.files[fname] = (fn, mode, copied)
543
543
544 def getfile(self, fname):
544 def getfile(self, fname):
545 if fname in self.data:
545 if fname in self.data:
546 return self.data[fname]
546 return self.data[fname]
547 if not self.opener or fname not in self.files:
547 if not self.opener or fname not in self.files:
548 return None, None, None
548 return None, None, None
549 fn, mode, copied = self.files[fname]
549 fn, mode, copied = self.files[fname]
550 return self.opener.read(fn), mode, copied
550 return self.opener.read(fn), mode, copied
551
551
552 def close(self):
552 def close(self):
553 if self.opener:
553 if self.opener:
554 shutil.rmtree(self.opener.base)
554 shutil.rmtree(self.opener.base)
555
555
556 class repobackend(abstractbackend):
556 class repobackend(abstractbackend):
557 def __init__(self, ui, repo, ctx, store):
557 def __init__(self, ui, repo, ctx, store):
558 super(repobackend, self).__init__(ui)
558 super(repobackend, self).__init__(ui)
559 self.repo = repo
559 self.repo = repo
560 self.ctx = ctx
560 self.ctx = ctx
561 self.store = store
561 self.store = store
562 self.changed = set()
562 self.changed = set()
563 self.removed = set()
563 self.removed = set()
564 self.copied = {}
564 self.copied = {}
565
565
566 def _checkknown(self, fname):
566 def _checkknown(self, fname):
567 if fname not in self.ctx:
567 if fname not in self.ctx:
568 raise PatchError(_('cannot patch %s: file is not tracked') % fname)
568 raise PatchError(_('cannot patch %s: file is not tracked') % fname)
569
569
570 def getfile(self, fname):
570 def getfile(self, fname):
571 try:
571 try:
572 fctx = self.ctx[fname]
572 fctx = self.ctx[fname]
573 except error.LookupError:
573 except error.LookupError:
574 return None, None
574 return None, None
575 flags = fctx.flags()
575 flags = fctx.flags()
576 return fctx.data(), ('l' in flags, 'x' in flags)
576 return fctx.data(), ('l' in flags, 'x' in flags)
577
577
578 def setfile(self, fname, data, mode, copysource):
578 def setfile(self, fname, data, mode, copysource):
579 if copysource:
579 if copysource:
580 self._checkknown(copysource)
580 self._checkknown(copysource)
581 if data is None:
581 if data is None:
582 data = self.ctx[fname].data()
582 data = self.ctx[fname].data()
583 self.store.setfile(fname, data, mode, copysource)
583 self.store.setfile(fname, data, mode, copysource)
584 self.changed.add(fname)
584 self.changed.add(fname)
585 if copysource:
585 if copysource:
586 self.copied[fname] = copysource
586 self.copied[fname] = copysource
587
587
588 def unlink(self, fname):
588 def unlink(self, fname):
589 self._checkknown(fname)
589 self._checkknown(fname)
590 self.removed.add(fname)
590 self.removed.add(fname)
591
591
592 def exists(self, fname):
592 def exists(self, fname):
593 return fname in self.ctx
593 return fname in self.ctx
594
594
595 def close(self):
595 def close(self):
596 return self.changed | self.removed
596 return self.changed | self.removed
597
597
598 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
598 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
599 unidesc = re.compile('@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@')
599 unidesc = re.compile('@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@')
600 contextdesc = re.compile('(?:---|\*\*\*) (\d+)(?:,(\d+))? (?:---|\*\*\*)')
600 contextdesc = re.compile('(?:---|\*\*\*) (\d+)(?:,(\d+))? (?:---|\*\*\*)')
601 eolmodes = ['strict', 'crlf', 'lf', 'auto']
601 eolmodes = ['strict', 'crlf', 'lf', 'auto']
602
602
603 class patchfile(object):
603 class patchfile(object):
604 def __init__(self, ui, gp, backend, store, eolmode='strict'):
604 def __init__(self, ui, gp, backend, store, eolmode='strict'):
605 self.fname = gp.path
605 self.fname = gp.path
606 self.eolmode = eolmode
606 self.eolmode = eolmode
607 self.eol = None
607 self.eol = None
608 self.backend = backend
608 self.backend = backend
609 self.ui = ui
609 self.ui = ui
610 self.lines = []
610 self.lines = []
611 self.exists = False
611 self.exists = False
612 self.missing = True
612 self.missing = True
613 self.mode = gp.mode
613 self.mode = gp.mode
614 self.copysource = gp.oldpath
614 self.copysource = gp.oldpath
615 self.create = gp.op in ('ADD', 'COPY', 'RENAME')
615 self.create = gp.op in ('ADD', 'COPY', 'RENAME')
616 self.remove = gp.op == 'DELETE'
616 self.remove = gp.op == 'DELETE'
617 if self.copysource is None:
617 if self.copysource is None:
618 data, mode = backend.getfile(self.fname)
618 data, mode = backend.getfile(self.fname)
619 else:
619 else:
620 data, mode = store.getfile(self.copysource)[:2]
620 data, mode = store.getfile(self.copysource)[:2]
621 if data is not None:
621 if data is not None:
622 self.exists = self.copysource is None or backend.exists(self.fname)
622 self.exists = self.copysource is None or backend.exists(self.fname)
623 self.missing = False
623 self.missing = False
624 if data:
624 if data:
625 self.lines = mdiff.splitnewlines(data)
625 self.lines = mdiff.splitnewlines(data)
626 if self.mode is None:
626 if self.mode is None:
627 self.mode = mode
627 self.mode = mode
628 if self.lines:
628 if self.lines:
629 # Normalize line endings
629 # Normalize line endings
630 if self.lines[0].endswith('\r\n'):
630 if self.lines[0].endswith('\r\n'):
631 self.eol = '\r\n'
631 self.eol = '\r\n'
632 elif self.lines[0].endswith('\n'):
632 elif self.lines[0].endswith('\n'):
633 self.eol = '\n'
633 self.eol = '\n'
634 if eolmode != 'strict':
634 if eolmode != 'strict':
635 nlines = []
635 nlines = []
636 for l in self.lines:
636 for l in self.lines:
637 if l.endswith('\r\n'):
637 if l.endswith('\r\n'):
638 l = l[:-2] + '\n'
638 l = l[:-2] + '\n'
639 nlines.append(l)
639 nlines.append(l)
640 self.lines = nlines
640 self.lines = nlines
641 else:
641 else:
642 if self.create:
642 if self.create:
643 self.missing = False
643 self.missing = False
644 if self.mode is None:
644 if self.mode is None:
645 self.mode = (False, False)
645 self.mode = (False, False)
646 if self.missing:
646 if self.missing:
647 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
647 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
648
648
649 self.hash = {}
649 self.hash = {}
650 self.dirty = 0
650 self.dirty = 0
651 self.offset = 0
651 self.offset = 0
652 self.skew = 0
652 self.skew = 0
653 self.rej = []
653 self.rej = []
654 self.fileprinted = False
654 self.fileprinted = False
655 self.printfile(False)
655 self.printfile(False)
656 self.hunks = 0
656 self.hunks = 0
657
657
658 def writelines(self, fname, lines, mode):
658 def writelines(self, fname, lines, mode):
659 if self.eolmode == 'auto':
659 if self.eolmode == 'auto':
660 eol = self.eol
660 eol = self.eol
661 elif self.eolmode == 'crlf':
661 elif self.eolmode == 'crlf':
662 eol = '\r\n'
662 eol = '\r\n'
663 else:
663 else:
664 eol = '\n'
664 eol = '\n'
665
665
666 if self.eolmode != 'strict' and eol and eol != '\n':
666 if self.eolmode != 'strict' and eol and eol != '\n':
667 rawlines = []
667 rawlines = []
668 for l in lines:
668 for l in lines:
669 if l and l[-1] == '\n':
669 if l and l[-1] == '\n':
670 l = l[:-1] + eol
670 l = l[:-1] + eol
671 rawlines.append(l)
671 rawlines.append(l)
672 lines = rawlines
672 lines = rawlines
673
673
674 self.backend.setfile(fname, ''.join(lines), mode, self.copysource)
674 self.backend.setfile(fname, ''.join(lines), mode, self.copysource)
675
675
676 def printfile(self, warn):
676 def printfile(self, warn):
677 if self.fileprinted:
677 if self.fileprinted:
678 return
678 return
679 if warn or self.ui.verbose:
679 if warn or self.ui.verbose:
680 self.fileprinted = True
680 self.fileprinted = True
681 s = _("patching file %s\n") % self.fname
681 s = _("patching file %s\n") % self.fname
682 if warn:
682 if warn:
683 self.ui.warn(s)
683 self.ui.warn(s)
684 else:
684 else:
685 self.ui.note(s)
685 self.ui.note(s)
686
686
687
687
688 def findlines(self, l, linenum):
688 def findlines(self, l, linenum):
689 # looks through the hash and finds candidate lines. The
689 # looks through the hash and finds candidate lines. The
690 # result is a list of line numbers sorted based on distance
690 # result is a list of line numbers sorted based on distance
691 # from linenum
691 # from linenum
692
692
693 cand = self.hash.get(l, [])
693 cand = self.hash.get(l, [])
694 if len(cand) > 1:
694 if len(cand) > 1:
695 # resort our list of potentials forward then back.
695 # resort our list of potentials forward then back.
696 cand.sort(key=lambda x: abs(x - linenum))
696 cand.sort(key=lambda x: abs(x - linenum))
697 return cand
697 return cand
698
698
699 def write_rej(self):
699 def write_rej(self):
700 # our rejects are a little different from patch(1). This always
700 # our rejects are a little different from patch(1). This always
701 # creates rejects in the same form as the original patch. A file
701 # creates rejects in the same form as the original patch. A file
702 # header is inserted so that you can run the reject through patch again
702 # header is inserted so that you can run the reject through patch again
703 # without having to type the filename.
703 # without having to type the filename.
704 if not self.rej:
704 if not self.rej:
705 return
705 return
706 base = os.path.basename(self.fname)
706 base = os.path.basename(self.fname)
707 lines = ["--- %s\n+++ %s\n" % (base, base)]
707 lines = ["--- %s\n+++ %s\n" % (base, base)]
708 for x in self.rej:
708 for x in self.rej:
709 for l in x.hunk:
709 for l in x.hunk:
710 lines.append(l)
710 lines.append(l)
711 if l[-1] != '\n':
711 if l[-1] != '\n':
712 lines.append("\n\ No newline at end of file\n")
712 lines.append("\n\ No newline at end of file\n")
713 self.backend.writerej(self.fname, len(self.rej), self.hunks, lines)
713 self.backend.writerej(self.fname, len(self.rej), self.hunks, lines)
714
714
715 def apply(self, h):
715 def apply(self, h):
716 if not h.complete():
716 if not h.complete():
717 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
717 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
718 (h.number, h.desc, len(h.a), h.lena, len(h.b),
718 (h.number, h.desc, len(h.a), h.lena, len(h.b),
719 h.lenb))
719 h.lenb))
720
720
721 self.hunks += 1
721 self.hunks += 1
722
722
723 if self.missing:
723 if self.missing:
724 self.rej.append(h)
724 self.rej.append(h)
725 return -1
725 return -1
726
726
727 if self.exists and self.create:
727 if self.exists and self.create:
728 if self.copysource:
728 if self.copysource:
729 self.ui.warn(_("cannot create %s: destination already "
729 self.ui.warn(_("cannot create %s: destination already "
730 "exists\n") % self.fname)
730 "exists\n") % self.fname)
731 else:
731 else:
732 self.ui.warn(_("file %s already exists\n") % self.fname)
732 self.ui.warn(_("file %s already exists\n") % self.fname)
733 self.rej.append(h)
733 self.rej.append(h)
734 return -1
734 return -1
735
735
736 if isinstance(h, binhunk):
736 if isinstance(h, binhunk):
737 if self.remove:
737 if self.remove:
738 self.backend.unlink(self.fname)
738 self.backend.unlink(self.fname)
739 else:
739 else:
740 l = h.new(self.lines)
740 l = h.new(self.lines)
741 self.lines[:] = l
741 self.lines[:] = l
742 self.offset += len(l)
742 self.offset += len(l)
743 self.dirty = True
743 self.dirty = True
744 return 0
744 return 0
745
745
746 horig = h
746 horig = h
747 if (self.eolmode in ('crlf', 'lf')
747 if (self.eolmode in ('crlf', 'lf')
748 or self.eolmode == 'auto' and self.eol):
748 or self.eolmode == 'auto' and self.eol):
749 # If new eols are going to be normalized, then normalize
749 # If new eols are going to be normalized, then normalize
750 # hunk data before patching. Otherwise, preserve input
750 # hunk data before patching. Otherwise, preserve input
751 # line-endings.
751 # line-endings.
752 h = h.getnormalized()
752 h = h.getnormalized()
753
753
754 # fast case first, no offsets, no fuzz
754 # fast case first, no offsets, no fuzz
755 old, oldstart, new, newstart = h.fuzzit(0, False)
755 old, oldstart, new, newstart = h.fuzzit(0, False)
756 oldstart += self.offset
756 oldstart += self.offset
757 orig_start = oldstart
757 orig_start = oldstart
758 # if there's skew we want to emit the "(offset %d lines)" even
758 # if there's skew we want to emit the "(offset %d lines)" even
759 # when the hunk cleanly applies at start + skew, so skip the
759 # when the hunk cleanly applies at start + skew, so skip the
760 # fast case code
760 # fast case code
761 if (self.skew == 0 and
761 if (self.skew == 0 and
762 diffhelpers.testhunk(old, self.lines, oldstart) == 0):
762 diffhelpers.testhunk(old, self.lines, oldstart) == 0):
763 if self.remove:
763 if self.remove:
764 self.backend.unlink(self.fname)
764 self.backend.unlink(self.fname)
765 else:
765 else:
766 self.lines[oldstart:oldstart + len(old)] = new
766 self.lines[oldstart:oldstart + len(old)] = new
767 self.offset += len(new) - len(old)
767 self.offset += len(new) - len(old)
768 self.dirty = True
768 self.dirty = True
769 return 0
769 return 0
770
770
771 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
771 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
772 self.hash = {}
772 self.hash = {}
773 for x, s in enumerate(self.lines):
773 for x, s in enumerate(self.lines):
774 self.hash.setdefault(s, []).append(x)
774 self.hash.setdefault(s, []).append(x)
775
775
776 for fuzzlen in xrange(3):
776 for fuzzlen in xrange(self.ui.configint("patch", "fuzz", 2) + 1):
777 for toponly in [True, False]:
777 for toponly in [True, False]:
778 old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly)
778 old, oldstart, new, newstart = h.fuzzit(fuzzlen, toponly)
779 oldstart = oldstart + self.offset + self.skew
779 oldstart = oldstart + self.offset + self.skew
780 oldstart = min(oldstart, len(self.lines))
780 oldstart = min(oldstart, len(self.lines))
781 if old:
781 if old:
782 cand = self.findlines(old[0][1:], oldstart)
782 cand = self.findlines(old[0][1:], oldstart)
783 else:
783 else:
784 # Only adding lines with no or fuzzed context, just
784 # Only adding lines with no or fuzzed context, just
785 # take the skew in account
785 # take the skew in account
786 cand = [oldstart]
786 cand = [oldstart]
787
787
788 for l in cand:
788 for l in cand:
789 if not old or diffhelpers.testhunk(old, self.lines, l) == 0:
789 if not old or diffhelpers.testhunk(old, self.lines, l) == 0:
790 self.lines[l : l + len(old)] = new
790 self.lines[l : l + len(old)] = new
791 self.offset += len(new) - len(old)
791 self.offset += len(new) - len(old)
792 self.skew = l - orig_start
792 self.skew = l - orig_start
793 self.dirty = True
793 self.dirty = True
794 offset = l - orig_start - fuzzlen
794 offset = l - orig_start - fuzzlen
795 if fuzzlen:
795 if fuzzlen:
796 msg = _("Hunk #%d succeeded at %d "
796 msg = _("Hunk #%d succeeded at %d "
797 "with fuzz %d "
797 "with fuzz %d "
798 "(offset %d lines).\n")
798 "(offset %d lines).\n")
799 self.printfile(True)
799 self.printfile(True)
800 self.ui.warn(msg %
800 self.ui.warn(msg %
801 (h.number, l + 1, fuzzlen, offset))
801 (h.number, l + 1, fuzzlen, offset))
802 else:
802 else:
803 msg = _("Hunk #%d succeeded at %d "
803 msg = _("Hunk #%d succeeded at %d "
804 "(offset %d lines).\n")
804 "(offset %d lines).\n")
805 self.ui.note(msg % (h.number, l + 1, offset))
805 self.ui.note(msg % (h.number, l + 1, offset))
806 return fuzzlen
806 return fuzzlen
807 self.printfile(True)
807 self.printfile(True)
808 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
808 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
809 self.rej.append(horig)
809 self.rej.append(horig)
810 return -1
810 return -1
811
811
812 def close(self):
812 def close(self):
813 if self.dirty:
813 if self.dirty:
814 self.writelines(self.fname, self.lines, self.mode)
814 self.writelines(self.fname, self.lines, self.mode)
815 self.write_rej()
815 self.write_rej()
816 return len(self.rej)
816 return len(self.rej)
817
817
818 class header(object):
818 class header(object):
819 """patch header
819 """patch header
820 """
820 """
821 diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
821 diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
822 diff_re = re.compile('diff -r .* (.*)$')
822 diff_re = re.compile('diff -r .* (.*)$')
823 allhunks_re = re.compile('(?:index|deleted file) ')
823 allhunks_re = re.compile('(?:index|deleted file) ')
824 pretty_re = re.compile('(?:new file|deleted file) ')
824 pretty_re = re.compile('(?:new file|deleted file) ')
825 special_re = re.compile('(?:index|deleted|copy|rename) ')
825 special_re = re.compile('(?:index|deleted|copy|rename) ')
826 newfile_re = re.compile('(?:new file)')
826 newfile_re = re.compile('(?:new file)')
827
827
828 def __init__(self, header):
828 def __init__(self, header):
829 self.header = header
829 self.header = header
830 self.hunks = []
830 self.hunks = []
831
831
832 def binary(self):
832 def binary(self):
833 return any(h.startswith('index ') for h in self.header)
833 return any(h.startswith('index ') for h in self.header)
834
834
835 def pretty(self, fp):
835 def pretty(self, fp):
836 for h in self.header:
836 for h in self.header:
837 if h.startswith('index '):
837 if h.startswith('index '):
838 fp.write(_('this modifies a binary file (all or nothing)\n'))
838 fp.write(_('this modifies a binary file (all or nothing)\n'))
839 break
839 break
840 if self.pretty_re.match(h):
840 if self.pretty_re.match(h):
841 fp.write(h)
841 fp.write(h)
842 if self.binary():
842 if self.binary():
843 fp.write(_('this is a binary file\n'))
843 fp.write(_('this is a binary file\n'))
844 break
844 break
845 if h.startswith('---'):
845 if h.startswith('---'):
846 fp.write(_('%d hunks, %d lines changed\n') %
846 fp.write(_('%d hunks, %d lines changed\n') %
847 (len(self.hunks),
847 (len(self.hunks),
848 sum([max(h.added, h.removed) for h in self.hunks])))
848 sum([max(h.added, h.removed) for h in self.hunks])))
849 break
849 break
850 fp.write(h)
850 fp.write(h)
851
851
852 def write(self, fp):
852 def write(self, fp):
853 fp.write(''.join(self.header))
853 fp.write(''.join(self.header))
854
854
855 def allhunks(self):
855 def allhunks(self):
856 return any(self.allhunks_re.match(h) for h in self.header)
856 return any(self.allhunks_re.match(h) for h in self.header)
857
857
858 def files(self):
858 def files(self):
859 match = self.diffgit_re.match(self.header[0])
859 match = self.diffgit_re.match(self.header[0])
860 if match:
860 if match:
861 fromfile, tofile = match.groups()
861 fromfile, tofile = match.groups()
862 if fromfile == tofile:
862 if fromfile == tofile:
863 return [fromfile]
863 return [fromfile]
864 return [fromfile, tofile]
864 return [fromfile, tofile]
865 else:
865 else:
866 return self.diff_re.match(self.header[0]).groups()
866 return self.diff_re.match(self.header[0]).groups()
867
867
868 def filename(self):
868 def filename(self):
869 return self.files()[-1]
869 return self.files()[-1]
870
870
871 def __repr__(self):
871 def __repr__(self):
872 return '<header %s>' % (' '.join(map(repr, self.files())))
872 return '<header %s>' % (' '.join(map(repr, self.files())))
873
873
874 def isnewfile(self):
874 def isnewfile(self):
875 return any(self.newfile_re.match(h) for h in self.header)
875 return any(self.newfile_re.match(h) for h in self.header)
876
876
877 def special(self):
877 def special(self):
878 # Special files are shown only at the header level and not at the hunk
878 # Special files are shown only at the header level and not at the hunk
879 # level for example a file that has been deleted is a special file.
879 # level for example a file that has been deleted is a special file.
880 # The user cannot change the content of the operation, in the case of
880 # The user cannot change the content of the operation, in the case of
881 # the deleted file he has to take the deletion or not take it, he
881 # the deleted file he has to take the deletion or not take it, he
882 # cannot take some of it.
882 # cannot take some of it.
883 # Newly added files are special if they are empty, they are not special
883 # Newly added files are special if they are empty, they are not special
884 # if they have some content as we want to be able to change it
884 # if they have some content as we want to be able to change it
885 nocontent = len(self.header) == 2
885 nocontent = len(self.header) == 2
886 emptynewfile = self.isnewfile() and nocontent
886 emptynewfile = self.isnewfile() and nocontent
887 return emptynewfile or \
887 return emptynewfile or \
888 any(self.special_re.match(h) for h in self.header)
888 any(self.special_re.match(h) for h in self.header)
889
889
890 class recordhunk(object):
890 class recordhunk(object):
891 """patch hunk
891 """patch hunk
892
892
893 XXX shouldn't we merge this with the other hunk class?
893 XXX shouldn't we merge this with the other hunk class?
894 """
894 """
895 maxcontext = 3
895 maxcontext = 3
896
896
897 def __init__(self, header, fromline, toline, proc, before, hunk, after):
897 def __init__(self, header, fromline, toline, proc, before, hunk, after):
898 def trimcontext(number, lines):
898 def trimcontext(number, lines):
899 delta = len(lines) - self.maxcontext
899 delta = len(lines) - self.maxcontext
900 if False and delta > 0:
900 if False and delta > 0:
901 return number + delta, lines[:self.maxcontext]
901 return number + delta, lines[:self.maxcontext]
902 return number, lines
902 return number, lines
903
903
904 self.header = header
904 self.header = header
905 self.fromline, self.before = trimcontext(fromline, before)
905 self.fromline, self.before = trimcontext(fromline, before)
906 self.toline, self.after = trimcontext(toline, after)
906 self.toline, self.after = trimcontext(toline, after)
907 self.proc = proc
907 self.proc = proc
908 self.hunk = hunk
908 self.hunk = hunk
909 self.added, self.removed = self.countchanges(self.hunk)
909 self.added, self.removed = self.countchanges(self.hunk)
910
910
911 def __eq__(self, v):
911 def __eq__(self, v):
912 if not isinstance(v, recordhunk):
912 if not isinstance(v, recordhunk):
913 return False
913 return False
914
914
915 return ((v.hunk == self.hunk) and
915 return ((v.hunk == self.hunk) and
916 (v.proc == self.proc) and
916 (v.proc == self.proc) and
917 (self.fromline == v.fromline) and
917 (self.fromline == v.fromline) and
918 (self.header.files() == v.header.files()))
918 (self.header.files() == v.header.files()))
919
919
920 def __hash__(self):
920 def __hash__(self):
921 return hash((tuple(self.hunk),
921 return hash((tuple(self.hunk),
922 tuple(self.header.files()),
922 tuple(self.header.files()),
923 self.fromline,
923 self.fromline,
924 self.proc))
924 self.proc))
925
925
926 def countchanges(self, hunk):
926 def countchanges(self, hunk):
927 """hunk -> (n+,n-)"""
927 """hunk -> (n+,n-)"""
928 add = len([h for h in hunk if h[0] == '+'])
928 add = len([h for h in hunk if h[0] == '+'])
929 rem = len([h for h in hunk if h[0] == '-'])
929 rem = len([h for h in hunk if h[0] == '-'])
930 return add, rem
930 return add, rem
931
931
932 def write(self, fp):
932 def write(self, fp):
933 delta = len(self.before) + len(self.after)
933 delta = len(self.before) + len(self.after)
934 if self.after and self.after[-1] == '\\ No newline at end of file\n':
934 if self.after and self.after[-1] == '\\ No newline at end of file\n':
935 delta -= 1
935 delta -= 1
936 fromlen = delta + self.removed
936 fromlen = delta + self.removed
937 tolen = delta + self.added
937 tolen = delta + self.added
938 fp.write('@@ -%d,%d +%d,%d @@%s\n' %
938 fp.write('@@ -%d,%d +%d,%d @@%s\n' %
939 (self.fromline, fromlen, self.toline, tolen,
939 (self.fromline, fromlen, self.toline, tolen,
940 self.proc and (' ' + self.proc)))
940 self.proc and (' ' + self.proc)))
941 fp.write(''.join(self.before + self.hunk + self.after))
941 fp.write(''.join(self.before + self.hunk + self.after))
942
942
943 pretty = write
943 pretty = write
944
944
945 def filename(self):
945 def filename(self):
946 return self.header.filename()
946 return self.header.filename()
947
947
948 def __repr__(self):
948 def __repr__(self):
949 return '<hunk %r@%d>' % (self.filename(), self.fromline)
949 return '<hunk %r@%d>' % (self.filename(), self.fromline)
950
950
951 def filterpatch(ui, headers, operation=None):
951 def filterpatch(ui, headers, operation=None):
952 """Interactively filter patch chunks into applied-only chunks"""
952 """Interactively filter patch chunks into applied-only chunks"""
953 if operation is None:
953 if operation is None:
954 operation = _('record')
954 operation = _('record')
955
955
956 def prompt(skipfile, skipall, query, chunk):
956 def prompt(skipfile, skipall, query, chunk):
957 """prompt query, and process base inputs
957 """prompt query, and process base inputs
958
958
959 - y/n for the rest of file
959 - y/n for the rest of file
960 - y/n for the rest
960 - y/n for the rest
961 - ? (help)
961 - ? (help)
962 - q (quit)
962 - q (quit)
963
963
964 Return True/False and possibly updated skipfile and skipall.
964 Return True/False and possibly updated skipfile and skipall.
965 """
965 """
966 newpatches = None
966 newpatches = None
967 if skipall is not None:
967 if skipall is not None:
968 return skipall, skipfile, skipall, newpatches
968 return skipall, skipfile, skipall, newpatches
969 if skipfile is not None:
969 if skipfile is not None:
970 return skipfile, skipfile, skipall, newpatches
970 return skipfile, skipfile, skipall, newpatches
971 while True:
971 while True:
972 resps = _('[Ynesfdaq?]'
972 resps = _('[Ynesfdaq?]'
973 '$$ &Yes, record this change'
973 '$$ &Yes, record this change'
974 '$$ &No, skip this change'
974 '$$ &No, skip this change'
975 '$$ &Edit this change manually'
975 '$$ &Edit this change manually'
976 '$$ &Skip remaining changes to this file'
976 '$$ &Skip remaining changes to this file'
977 '$$ Record remaining changes to this &file'
977 '$$ Record remaining changes to this &file'
978 '$$ &Done, skip remaining changes and files'
978 '$$ &Done, skip remaining changes and files'
979 '$$ Record &all changes to all remaining files'
979 '$$ Record &all changes to all remaining files'
980 '$$ &Quit, recording no changes'
980 '$$ &Quit, recording no changes'
981 '$$ &? (display help)')
981 '$$ &? (display help)')
982 r = ui.promptchoice("%s %s" % (query, resps))
982 r = ui.promptchoice("%s %s" % (query, resps))
983 ui.write("\n")
983 ui.write("\n")
984 if r == 8: # ?
984 if r == 8: # ?
985 for c, t in ui.extractchoices(resps)[1]:
985 for c, t in ui.extractchoices(resps)[1]:
986 ui.write('%s - %s\n' % (c, t.lower()))
986 ui.write('%s - %s\n' % (c, t.lower()))
987 continue
987 continue
988 elif r == 0: # yes
988 elif r == 0: # yes
989 ret = True
989 ret = True
990 elif r == 1: # no
990 elif r == 1: # no
991 ret = False
991 ret = False
992 elif r == 2: # Edit patch
992 elif r == 2: # Edit patch
993 if chunk is None:
993 if chunk is None:
994 ui.write(_('cannot edit patch for whole file'))
994 ui.write(_('cannot edit patch for whole file'))
995 ui.write("\n")
995 ui.write("\n")
996 continue
996 continue
997 if chunk.header.binary():
997 if chunk.header.binary():
998 ui.write(_('cannot edit patch for binary file'))
998 ui.write(_('cannot edit patch for binary file'))
999 ui.write("\n")
999 ui.write("\n")
1000 continue
1000 continue
1001 # Patch comment based on the Git one (based on comment at end of
1001 # Patch comment based on the Git one (based on comment at end of
1002 # http://mercurial.selenic.com/wiki/RecordExtension)
1002 # http://mercurial.selenic.com/wiki/RecordExtension)
1003 phelp = '---' + _("""
1003 phelp = '---' + _("""
1004 To remove '-' lines, make them ' ' lines (context).
1004 To remove '-' lines, make them ' ' lines (context).
1005 To remove '+' lines, delete them.
1005 To remove '+' lines, delete them.
1006 Lines starting with # will be removed from the patch.
1006 Lines starting with # will be removed from the patch.
1007
1007
1008 If the patch applies cleanly, the edited hunk will immediately be
1008 If the patch applies cleanly, the edited hunk will immediately be
1009 added to the record list. If it does not apply cleanly, a rejects
1009 added to the record list. If it does not apply cleanly, a rejects
1010 file will be generated: you can use that when you try again. If
1010 file will be generated: you can use that when you try again. If
1011 all lines of the hunk are removed, then the edit is aborted and
1011 all lines of the hunk are removed, then the edit is aborted and
1012 the hunk is left unchanged.
1012 the hunk is left unchanged.
1013 """)
1013 """)
1014 (patchfd, patchfn) = tempfile.mkstemp(prefix="hg-editor-",
1014 (patchfd, patchfn) = tempfile.mkstemp(prefix="hg-editor-",
1015 suffix=".diff", text=True)
1015 suffix=".diff", text=True)
1016 ncpatchfp = None
1016 ncpatchfp = None
1017 try:
1017 try:
1018 # Write the initial patch
1018 # Write the initial patch
1019 f = os.fdopen(patchfd, "w")
1019 f = os.fdopen(patchfd, "w")
1020 chunk.header.write(f)
1020 chunk.header.write(f)
1021 chunk.write(f)
1021 chunk.write(f)
1022 f.write('\n'.join(['# ' + i for i in phelp.splitlines()]))
1022 f.write('\n'.join(['# ' + i for i in phelp.splitlines()]))
1023 f.close()
1023 f.close()
1024 # Start the editor and wait for it to complete
1024 # Start the editor and wait for it to complete
1025 editor = ui.geteditor()
1025 editor = ui.geteditor()
1026 ret = ui.system("%s \"%s\"" % (editor, patchfn),
1026 ret = ui.system("%s \"%s\"" % (editor, patchfn),
1027 environ={'HGUSER': ui.username()})
1027 environ={'HGUSER': ui.username()})
1028 if ret != 0:
1028 if ret != 0:
1029 ui.warn(_("editor exited with exit code %d\n") % ret)
1029 ui.warn(_("editor exited with exit code %d\n") % ret)
1030 continue
1030 continue
1031 # Remove comment lines
1031 # Remove comment lines
1032 patchfp = open(patchfn)
1032 patchfp = open(patchfn)
1033 ncpatchfp = cStringIO.StringIO()
1033 ncpatchfp = cStringIO.StringIO()
1034 for line in patchfp:
1034 for line in patchfp:
1035 if not line.startswith('#'):
1035 if not line.startswith('#'):
1036 ncpatchfp.write(line)
1036 ncpatchfp.write(line)
1037 patchfp.close()
1037 patchfp.close()
1038 ncpatchfp.seek(0)
1038 ncpatchfp.seek(0)
1039 newpatches = parsepatch(ncpatchfp)
1039 newpatches = parsepatch(ncpatchfp)
1040 finally:
1040 finally:
1041 os.unlink(patchfn)
1041 os.unlink(patchfn)
1042 del ncpatchfp
1042 del ncpatchfp
1043 # Signal that the chunk shouldn't be applied as-is, but
1043 # Signal that the chunk shouldn't be applied as-is, but
1044 # provide the new patch to be used instead.
1044 # provide the new patch to be used instead.
1045 ret = False
1045 ret = False
1046 elif r == 3: # Skip
1046 elif r == 3: # Skip
1047 ret = skipfile = False
1047 ret = skipfile = False
1048 elif r == 4: # file (Record remaining)
1048 elif r == 4: # file (Record remaining)
1049 ret = skipfile = True
1049 ret = skipfile = True
1050 elif r == 5: # done, skip remaining
1050 elif r == 5: # done, skip remaining
1051 ret = skipall = False
1051 ret = skipall = False
1052 elif r == 6: # all
1052 elif r == 6: # all
1053 ret = skipall = True
1053 ret = skipall = True
1054 elif r == 7: # quit
1054 elif r == 7: # quit
1055 raise util.Abort(_('user quit'))
1055 raise util.Abort(_('user quit'))
1056 return ret, skipfile, skipall, newpatches
1056 return ret, skipfile, skipall, newpatches
1057
1057
1058 seen = set()
1058 seen = set()
1059 applied = {} # 'filename' -> [] of chunks
1059 applied = {} # 'filename' -> [] of chunks
1060 skipfile, skipall = None, None
1060 skipfile, skipall = None, None
1061 pos, total = 1, sum(len(h.hunks) for h in headers)
1061 pos, total = 1, sum(len(h.hunks) for h in headers)
1062 for h in headers:
1062 for h in headers:
1063 pos += len(h.hunks)
1063 pos += len(h.hunks)
1064 skipfile = None
1064 skipfile = None
1065 fixoffset = 0
1065 fixoffset = 0
1066 hdr = ''.join(h.header)
1066 hdr = ''.join(h.header)
1067 if hdr in seen:
1067 if hdr in seen:
1068 continue
1068 continue
1069 seen.add(hdr)
1069 seen.add(hdr)
1070 if skipall is None:
1070 if skipall is None:
1071 h.pretty(ui)
1071 h.pretty(ui)
1072 msg = (_('examine changes to %s?') %
1072 msg = (_('examine changes to %s?') %
1073 _(' and ').join("'%s'" % f for f in h.files()))
1073 _(' and ').join("'%s'" % f for f in h.files()))
1074 r, skipfile, skipall, np = prompt(skipfile, skipall, msg, None)
1074 r, skipfile, skipall, np = prompt(skipfile, skipall, msg, None)
1075 if not r:
1075 if not r:
1076 continue
1076 continue
1077 applied[h.filename()] = [h]
1077 applied[h.filename()] = [h]
1078 if h.allhunks():
1078 if h.allhunks():
1079 applied[h.filename()] += h.hunks
1079 applied[h.filename()] += h.hunks
1080 continue
1080 continue
1081 for i, chunk in enumerate(h.hunks):
1081 for i, chunk in enumerate(h.hunks):
1082 if skipfile is None and skipall is None:
1082 if skipfile is None and skipall is None:
1083 chunk.pretty(ui)
1083 chunk.pretty(ui)
1084 if total == 1:
1084 if total == 1:
1085 msg = _("record this change to '%s'?") % chunk.filename()
1085 msg = _("record this change to '%s'?") % chunk.filename()
1086 else:
1086 else:
1087 idx = pos - len(h.hunks) + i
1087 idx = pos - len(h.hunks) + i
1088 msg = _("record change %d/%d to '%s'?") % (idx, total,
1088 msg = _("record change %d/%d to '%s'?") % (idx, total,
1089 chunk.filename())
1089 chunk.filename())
1090 r, skipfile, skipall, newpatches = prompt(skipfile,
1090 r, skipfile, skipall, newpatches = prompt(skipfile,
1091 skipall, msg, chunk)
1091 skipall, msg, chunk)
1092 if r:
1092 if r:
1093 if fixoffset:
1093 if fixoffset:
1094 chunk = copy.copy(chunk)
1094 chunk = copy.copy(chunk)
1095 chunk.toline += fixoffset
1095 chunk.toline += fixoffset
1096 applied[chunk.filename()].append(chunk)
1096 applied[chunk.filename()].append(chunk)
1097 elif newpatches is not None:
1097 elif newpatches is not None:
1098 for newpatch in newpatches:
1098 for newpatch in newpatches:
1099 for newhunk in newpatch.hunks:
1099 for newhunk in newpatch.hunks:
1100 if fixoffset:
1100 if fixoffset:
1101 newhunk.toline += fixoffset
1101 newhunk.toline += fixoffset
1102 applied[newhunk.filename()].append(newhunk)
1102 applied[newhunk.filename()].append(newhunk)
1103 else:
1103 else:
1104 fixoffset += chunk.removed - chunk.added
1104 fixoffset += chunk.removed - chunk.added
1105 return sum([h for h in applied.itervalues()
1105 return sum([h for h in applied.itervalues()
1106 if h[0].special() or len(h) > 1], [])
1106 if h[0].special() or len(h) > 1], [])
1107 class hunk(object):
1107 class hunk(object):
1108 def __init__(self, desc, num, lr, context):
1108 def __init__(self, desc, num, lr, context):
1109 self.number = num
1109 self.number = num
1110 self.desc = desc
1110 self.desc = desc
1111 self.hunk = [desc]
1111 self.hunk = [desc]
1112 self.a = []
1112 self.a = []
1113 self.b = []
1113 self.b = []
1114 self.starta = self.lena = None
1114 self.starta = self.lena = None
1115 self.startb = self.lenb = None
1115 self.startb = self.lenb = None
1116 if lr is not None:
1116 if lr is not None:
1117 if context:
1117 if context:
1118 self.read_context_hunk(lr)
1118 self.read_context_hunk(lr)
1119 else:
1119 else:
1120 self.read_unified_hunk(lr)
1120 self.read_unified_hunk(lr)
1121
1121
1122 def getnormalized(self):
1122 def getnormalized(self):
1123 """Return a copy with line endings normalized to LF."""
1123 """Return a copy with line endings normalized to LF."""
1124
1124
1125 def normalize(lines):
1125 def normalize(lines):
1126 nlines = []
1126 nlines = []
1127 for line in lines:
1127 for line in lines:
1128 if line.endswith('\r\n'):
1128 if line.endswith('\r\n'):
1129 line = line[:-2] + '\n'
1129 line = line[:-2] + '\n'
1130 nlines.append(line)
1130 nlines.append(line)
1131 return nlines
1131 return nlines
1132
1132
1133 # Dummy object, it is rebuilt manually
1133 # Dummy object, it is rebuilt manually
1134 nh = hunk(self.desc, self.number, None, None)
1134 nh = hunk(self.desc, self.number, None, None)
1135 nh.number = self.number
1135 nh.number = self.number
1136 nh.desc = self.desc
1136 nh.desc = self.desc
1137 nh.hunk = self.hunk
1137 nh.hunk = self.hunk
1138 nh.a = normalize(self.a)
1138 nh.a = normalize(self.a)
1139 nh.b = normalize(self.b)
1139 nh.b = normalize(self.b)
1140 nh.starta = self.starta
1140 nh.starta = self.starta
1141 nh.startb = self.startb
1141 nh.startb = self.startb
1142 nh.lena = self.lena
1142 nh.lena = self.lena
1143 nh.lenb = self.lenb
1143 nh.lenb = self.lenb
1144 return nh
1144 return nh
1145
1145
1146 def read_unified_hunk(self, lr):
1146 def read_unified_hunk(self, lr):
1147 m = unidesc.match(self.desc)
1147 m = unidesc.match(self.desc)
1148 if not m:
1148 if not m:
1149 raise PatchError(_("bad hunk #%d") % self.number)
1149 raise PatchError(_("bad hunk #%d") % self.number)
1150 self.starta, self.lena, self.startb, self.lenb = m.groups()
1150 self.starta, self.lena, self.startb, self.lenb = m.groups()
1151 if self.lena is None:
1151 if self.lena is None:
1152 self.lena = 1
1152 self.lena = 1
1153 else:
1153 else:
1154 self.lena = int(self.lena)
1154 self.lena = int(self.lena)
1155 if self.lenb is None:
1155 if self.lenb is None:
1156 self.lenb = 1
1156 self.lenb = 1
1157 else:
1157 else:
1158 self.lenb = int(self.lenb)
1158 self.lenb = int(self.lenb)
1159 self.starta = int(self.starta)
1159 self.starta = int(self.starta)
1160 self.startb = int(self.startb)
1160 self.startb = int(self.startb)
1161 diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a,
1161 diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a,
1162 self.b)
1162 self.b)
1163 # if we hit eof before finishing out the hunk, the last line will
1163 # if we hit eof before finishing out the hunk, the last line will
1164 # be zero length. Lets try to fix it up.
1164 # be zero length. Lets try to fix it up.
1165 while len(self.hunk[-1]) == 0:
1165 while len(self.hunk[-1]) == 0:
1166 del self.hunk[-1]
1166 del self.hunk[-1]
1167 del self.a[-1]
1167 del self.a[-1]
1168 del self.b[-1]
1168 del self.b[-1]
1169 self.lena -= 1
1169 self.lena -= 1
1170 self.lenb -= 1
1170 self.lenb -= 1
1171 self._fixnewline(lr)
1171 self._fixnewline(lr)
1172
1172
1173 def read_context_hunk(self, lr):
1173 def read_context_hunk(self, lr):
1174 self.desc = lr.readline()
1174 self.desc = lr.readline()
1175 m = contextdesc.match(self.desc)
1175 m = contextdesc.match(self.desc)
1176 if not m:
1176 if not m:
1177 raise PatchError(_("bad hunk #%d") % self.number)
1177 raise PatchError(_("bad hunk #%d") % self.number)
1178 self.starta, aend = m.groups()
1178 self.starta, aend = m.groups()
1179 self.starta = int(self.starta)
1179 self.starta = int(self.starta)
1180 if aend is None:
1180 if aend is None:
1181 aend = self.starta
1181 aend = self.starta
1182 self.lena = int(aend) - self.starta
1182 self.lena = int(aend) - self.starta
1183 if self.starta:
1183 if self.starta:
1184 self.lena += 1
1184 self.lena += 1
1185 for x in xrange(self.lena):
1185 for x in xrange(self.lena):
1186 l = lr.readline()
1186 l = lr.readline()
1187 if l.startswith('---'):
1187 if l.startswith('---'):
1188 # lines addition, old block is empty
1188 # lines addition, old block is empty
1189 lr.push(l)
1189 lr.push(l)
1190 break
1190 break
1191 s = l[2:]
1191 s = l[2:]
1192 if l.startswith('- ') or l.startswith('! '):
1192 if l.startswith('- ') or l.startswith('! '):
1193 u = '-' + s
1193 u = '-' + s
1194 elif l.startswith(' '):
1194 elif l.startswith(' '):
1195 u = ' ' + s
1195 u = ' ' + s
1196 else:
1196 else:
1197 raise PatchError(_("bad hunk #%d old text line %d") %
1197 raise PatchError(_("bad hunk #%d old text line %d") %
1198 (self.number, x))
1198 (self.number, x))
1199 self.a.append(u)
1199 self.a.append(u)
1200 self.hunk.append(u)
1200 self.hunk.append(u)
1201
1201
1202 l = lr.readline()
1202 l = lr.readline()
1203 if l.startswith('\ '):
1203 if l.startswith('\ '):
1204 s = self.a[-1][:-1]
1204 s = self.a[-1][:-1]
1205 self.a[-1] = s
1205 self.a[-1] = s
1206 self.hunk[-1] = s
1206 self.hunk[-1] = s
1207 l = lr.readline()
1207 l = lr.readline()
1208 m = contextdesc.match(l)
1208 m = contextdesc.match(l)
1209 if not m:
1209 if not m:
1210 raise PatchError(_("bad hunk #%d") % self.number)
1210 raise PatchError(_("bad hunk #%d") % self.number)
1211 self.startb, bend = m.groups()
1211 self.startb, bend = m.groups()
1212 self.startb = int(self.startb)
1212 self.startb = int(self.startb)
1213 if bend is None:
1213 if bend is None:
1214 bend = self.startb
1214 bend = self.startb
1215 self.lenb = int(bend) - self.startb
1215 self.lenb = int(bend) - self.startb
1216 if self.startb:
1216 if self.startb:
1217 self.lenb += 1
1217 self.lenb += 1
1218 hunki = 1
1218 hunki = 1
1219 for x in xrange(self.lenb):
1219 for x in xrange(self.lenb):
1220 l = lr.readline()
1220 l = lr.readline()
1221 if l.startswith('\ '):
1221 if l.startswith('\ '):
1222 # XXX: the only way to hit this is with an invalid line range.
1222 # XXX: the only way to hit this is with an invalid line range.
1223 # The no-eol marker is not counted in the line range, but I
1223 # The no-eol marker is not counted in the line range, but I
1224 # guess there are diff(1) out there which behave differently.
1224 # guess there are diff(1) out there which behave differently.
1225 s = self.b[-1][:-1]
1225 s = self.b[-1][:-1]
1226 self.b[-1] = s
1226 self.b[-1] = s
1227 self.hunk[hunki - 1] = s
1227 self.hunk[hunki - 1] = s
1228 continue
1228 continue
1229 if not l:
1229 if not l:
1230 # line deletions, new block is empty and we hit EOF
1230 # line deletions, new block is empty and we hit EOF
1231 lr.push(l)
1231 lr.push(l)
1232 break
1232 break
1233 s = l[2:]
1233 s = l[2:]
1234 if l.startswith('+ ') or l.startswith('! '):
1234 if l.startswith('+ ') or l.startswith('! '):
1235 u = '+' + s
1235 u = '+' + s
1236 elif l.startswith(' '):
1236 elif l.startswith(' '):
1237 u = ' ' + s
1237 u = ' ' + s
1238 elif len(self.b) == 0:
1238 elif len(self.b) == 0:
1239 # line deletions, new block is empty
1239 # line deletions, new block is empty
1240 lr.push(l)
1240 lr.push(l)
1241 break
1241 break
1242 else:
1242 else:
1243 raise PatchError(_("bad hunk #%d old text line %d") %
1243 raise PatchError(_("bad hunk #%d old text line %d") %
1244 (self.number, x))
1244 (self.number, x))
1245 self.b.append(s)
1245 self.b.append(s)
1246 while True:
1246 while True:
1247 if hunki >= len(self.hunk):
1247 if hunki >= len(self.hunk):
1248 h = ""
1248 h = ""
1249 else:
1249 else:
1250 h = self.hunk[hunki]
1250 h = self.hunk[hunki]
1251 hunki += 1
1251 hunki += 1
1252 if h == u:
1252 if h == u:
1253 break
1253 break
1254 elif h.startswith('-'):
1254 elif h.startswith('-'):
1255 continue
1255 continue
1256 else:
1256 else:
1257 self.hunk.insert(hunki - 1, u)
1257 self.hunk.insert(hunki - 1, u)
1258 break
1258 break
1259
1259
1260 if not self.a:
1260 if not self.a:
1261 # this happens when lines were only added to the hunk
1261 # this happens when lines were only added to the hunk
1262 for x in self.hunk:
1262 for x in self.hunk:
1263 if x.startswith('-') or x.startswith(' '):
1263 if x.startswith('-') or x.startswith(' '):
1264 self.a.append(x)
1264 self.a.append(x)
1265 if not self.b:
1265 if not self.b:
1266 # this happens when lines were only deleted from the hunk
1266 # this happens when lines were only deleted from the hunk
1267 for x in self.hunk:
1267 for x in self.hunk:
1268 if x.startswith('+') or x.startswith(' '):
1268 if x.startswith('+') or x.startswith(' '):
1269 self.b.append(x[1:])
1269 self.b.append(x[1:])
1270 # @@ -start,len +start,len @@
1270 # @@ -start,len +start,len @@
1271 self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
1271 self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
1272 self.startb, self.lenb)
1272 self.startb, self.lenb)
1273 self.hunk[0] = self.desc
1273 self.hunk[0] = self.desc
1274 self._fixnewline(lr)
1274 self._fixnewline(lr)
1275
1275
1276 def _fixnewline(self, lr):
1276 def _fixnewline(self, lr):
1277 l = lr.readline()
1277 l = lr.readline()
1278 if l.startswith('\ '):
1278 if l.startswith('\ '):
1279 diffhelpers.fix_newline(self.hunk, self.a, self.b)
1279 diffhelpers.fix_newline(self.hunk, self.a, self.b)
1280 else:
1280 else:
1281 lr.push(l)
1281 lr.push(l)
1282
1282
1283 def complete(self):
1283 def complete(self):
1284 return len(self.a) == self.lena and len(self.b) == self.lenb
1284 return len(self.a) == self.lena and len(self.b) == self.lenb
1285
1285
1286 def _fuzzit(self, old, new, fuzz, toponly):
1286 def _fuzzit(self, old, new, fuzz, toponly):
1287 # this removes context lines from the top and bottom of list 'l'. It
1287 # this removes context lines from the top and bottom of list 'l'. It
1288 # checks the hunk to make sure only context lines are removed, and then
1288 # checks the hunk to make sure only context lines are removed, and then
1289 # returns a new shortened list of lines.
1289 # returns a new shortened list of lines.
1290 fuzz = min(fuzz, len(old))
1290 fuzz = min(fuzz, len(old))
1291 if fuzz:
1291 if fuzz:
1292 top = 0
1292 top = 0
1293 bot = 0
1293 bot = 0
1294 hlen = len(self.hunk)
1294 hlen = len(self.hunk)
1295 for x in xrange(hlen - 1):
1295 for x in xrange(hlen - 1):
1296 # the hunk starts with the @@ line, so use x+1
1296 # the hunk starts with the @@ line, so use x+1
1297 if self.hunk[x + 1][0] == ' ':
1297 if self.hunk[x + 1][0] == ' ':
1298 top += 1
1298 top += 1
1299 else:
1299 else:
1300 break
1300 break
1301 if not toponly:
1301 if not toponly:
1302 for x in xrange(hlen - 1):
1302 for x in xrange(hlen - 1):
1303 if self.hunk[hlen - bot - 1][0] == ' ':
1303 if self.hunk[hlen - bot - 1][0] == ' ':
1304 bot += 1
1304 bot += 1
1305 else:
1305 else:
1306 break
1306 break
1307
1307
1308 bot = min(fuzz, bot)
1308 bot = min(fuzz, bot)
1309 top = min(fuzz, top)
1309 top = min(fuzz, top)
1310 return old[top:len(old) - bot], new[top:len(new) - bot], top
1310 return old[top:len(old) - bot], new[top:len(new) - bot], top
1311 return old, new, 0
1311 return old, new, 0
1312
1312
1313 def fuzzit(self, fuzz, toponly):
1313 def fuzzit(self, fuzz, toponly):
1314 old, new, top = self._fuzzit(self.a, self.b, fuzz, toponly)
1314 old, new, top = self._fuzzit(self.a, self.b, fuzz, toponly)
1315 oldstart = self.starta + top
1315 oldstart = self.starta + top
1316 newstart = self.startb + top
1316 newstart = self.startb + top
1317 # zero length hunk ranges already have their start decremented
1317 # zero length hunk ranges already have their start decremented
1318 if self.lena and oldstart > 0:
1318 if self.lena and oldstart > 0:
1319 oldstart -= 1
1319 oldstart -= 1
1320 if self.lenb and newstart > 0:
1320 if self.lenb and newstart > 0:
1321 newstart -= 1
1321 newstart -= 1
1322 return old, oldstart, new, newstart
1322 return old, oldstart, new, newstart
1323
1323
1324 class binhunk(object):
1324 class binhunk(object):
1325 'A binary patch file.'
1325 'A binary patch file.'
1326 def __init__(self, lr, fname):
1326 def __init__(self, lr, fname):
1327 self.text = None
1327 self.text = None
1328 self.delta = False
1328 self.delta = False
1329 self.hunk = ['GIT binary patch\n']
1329 self.hunk = ['GIT binary patch\n']
1330 self._fname = fname
1330 self._fname = fname
1331 self._read(lr)
1331 self._read(lr)
1332
1332
1333 def complete(self):
1333 def complete(self):
1334 return self.text is not None
1334 return self.text is not None
1335
1335
1336 def new(self, lines):
1336 def new(self, lines):
1337 if self.delta:
1337 if self.delta:
1338 return [applybindelta(self.text, ''.join(lines))]
1338 return [applybindelta(self.text, ''.join(lines))]
1339 return [self.text]
1339 return [self.text]
1340
1340
1341 def _read(self, lr):
1341 def _read(self, lr):
1342 def getline(lr, hunk):
1342 def getline(lr, hunk):
1343 l = lr.readline()
1343 l = lr.readline()
1344 hunk.append(l)
1344 hunk.append(l)
1345 return l.rstrip('\r\n')
1345 return l.rstrip('\r\n')
1346
1346
1347 size = 0
1347 size = 0
1348 while True:
1348 while True:
1349 line = getline(lr, self.hunk)
1349 line = getline(lr, self.hunk)
1350 if not line:
1350 if not line:
1351 raise PatchError(_('could not extract "%s" binary data')
1351 raise PatchError(_('could not extract "%s" binary data')
1352 % self._fname)
1352 % self._fname)
1353 if line.startswith('literal '):
1353 if line.startswith('literal '):
1354 size = int(line[8:].rstrip())
1354 size = int(line[8:].rstrip())
1355 break
1355 break
1356 if line.startswith('delta '):
1356 if line.startswith('delta '):
1357 size = int(line[6:].rstrip())
1357 size = int(line[6:].rstrip())
1358 self.delta = True
1358 self.delta = True
1359 break
1359 break
1360 dec = []
1360 dec = []
1361 line = getline(lr, self.hunk)
1361 line = getline(lr, self.hunk)
1362 while len(line) > 1:
1362 while len(line) > 1:
1363 l = line[0]
1363 l = line[0]
1364 if l <= 'Z' and l >= 'A':
1364 if l <= 'Z' and l >= 'A':
1365 l = ord(l) - ord('A') + 1
1365 l = ord(l) - ord('A') + 1
1366 else:
1366 else:
1367 l = ord(l) - ord('a') + 27
1367 l = ord(l) - ord('a') + 27
1368 try:
1368 try:
1369 dec.append(base85.b85decode(line[1:])[:l])
1369 dec.append(base85.b85decode(line[1:])[:l])
1370 except ValueError, e:
1370 except ValueError, e:
1371 raise PatchError(_('could not decode "%s" binary patch: %s')
1371 raise PatchError(_('could not decode "%s" binary patch: %s')
1372 % (self._fname, str(e)))
1372 % (self._fname, str(e)))
1373 line = getline(lr, self.hunk)
1373 line = getline(lr, self.hunk)
1374 text = zlib.decompress(''.join(dec))
1374 text = zlib.decompress(''.join(dec))
1375 if len(text) != size:
1375 if len(text) != size:
1376 raise PatchError(_('"%s" length is %d bytes, should be %d')
1376 raise PatchError(_('"%s" length is %d bytes, should be %d')
1377 % (self._fname, len(text), size))
1377 % (self._fname, len(text), size))
1378 self.text = text
1378 self.text = text
1379
1379
1380 def parsefilename(str):
1380 def parsefilename(str):
1381 # --- filename \t|space stuff
1381 # --- filename \t|space stuff
1382 s = str[4:].rstrip('\r\n')
1382 s = str[4:].rstrip('\r\n')
1383 i = s.find('\t')
1383 i = s.find('\t')
1384 if i < 0:
1384 if i < 0:
1385 i = s.find(' ')
1385 i = s.find(' ')
1386 if i < 0:
1386 if i < 0:
1387 return s
1387 return s
1388 return s[:i]
1388 return s[:i]
1389
1389
1390 def reversehunks(hunks):
1390 def reversehunks(hunks):
1391 '''reverse the signs in the hunks given as argument
1391 '''reverse the signs in the hunks given as argument
1392
1392
1393 This function operates on hunks coming out of patch.filterpatch, that is
1393 This function operates on hunks coming out of patch.filterpatch, that is
1394 a list of the form: [header1, hunk1, hunk2, header2...]. Example usage:
1394 a list of the form: [header1, hunk1, hunk2, header2...]. Example usage:
1395
1395
1396 >>> rawpatch = """diff --git a/folder1/g b/folder1/g
1396 >>> rawpatch = """diff --git a/folder1/g b/folder1/g
1397 ... --- a/folder1/g
1397 ... --- a/folder1/g
1398 ... +++ b/folder1/g
1398 ... +++ b/folder1/g
1399 ... @@ -1,7 +1,7 @@
1399 ... @@ -1,7 +1,7 @@
1400 ... +firstline
1400 ... +firstline
1401 ... c
1401 ... c
1402 ... 1
1402 ... 1
1403 ... 2
1403 ... 2
1404 ... + 3
1404 ... + 3
1405 ... -4
1405 ... -4
1406 ... 5
1406 ... 5
1407 ... d
1407 ... d
1408 ... +lastline"""
1408 ... +lastline"""
1409 >>> hunks = parsepatch(rawpatch)
1409 >>> hunks = parsepatch(rawpatch)
1410 >>> hunkscomingfromfilterpatch = []
1410 >>> hunkscomingfromfilterpatch = []
1411 >>> for h in hunks:
1411 >>> for h in hunks:
1412 ... hunkscomingfromfilterpatch.append(h)
1412 ... hunkscomingfromfilterpatch.append(h)
1413 ... hunkscomingfromfilterpatch.extend(h.hunks)
1413 ... hunkscomingfromfilterpatch.extend(h.hunks)
1414
1414
1415 >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
1415 >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
1416 >>> fp = cStringIO.StringIO()
1416 >>> fp = cStringIO.StringIO()
1417 >>> for c in reversedhunks:
1417 >>> for c in reversedhunks:
1418 ... c.write(fp)
1418 ... c.write(fp)
1419 >>> fp.seek(0)
1419 >>> fp.seek(0)
1420 >>> reversedpatch = fp.read()
1420 >>> reversedpatch = fp.read()
1421 >>> print reversedpatch
1421 >>> print reversedpatch
1422 diff --git a/folder1/g b/folder1/g
1422 diff --git a/folder1/g b/folder1/g
1423 --- a/folder1/g
1423 --- a/folder1/g
1424 +++ b/folder1/g
1424 +++ b/folder1/g
1425 @@ -1,4 +1,3 @@
1425 @@ -1,4 +1,3 @@
1426 -firstline
1426 -firstline
1427 c
1427 c
1428 1
1428 1
1429 2
1429 2
1430 @@ -1,6 +2,6 @@
1430 @@ -1,6 +2,6 @@
1431 c
1431 c
1432 1
1432 1
1433 2
1433 2
1434 - 3
1434 - 3
1435 +4
1435 +4
1436 5
1436 5
1437 d
1437 d
1438 @@ -5,3 +6,2 @@
1438 @@ -5,3 +6,2 @@
1439 5
1439 5
1440 d
1440 d
1441 -lastline
1441 -lastline
1442
1442
1443 '''
1443 '''
1444
1444
1445 import crecord as crecordmod
1445 import crecord as crecordmod
1446 newhunks = []
1446 newhunks = []
1447 for c in hunks:
1447 for c in hunks:
1448 if isinstance(c, crecordmod.uihunk):
1448 if isinstance(c, crecordmod.uihunk):
1449 # curses hunks encapsulate the record hunk in _hunk
1449 # curses hunks encapsulate the record hunk in _hunk
1450 c = c._hunk
1450 c = c._hunk
1451 if isinstance(c, recordhunk):
1451 if isinstance(c, recordhunk):
1452 for j, line in enumerate(c.hunk):
1452 for j, line in enumerate(c.hunk):
1453 if line.startswith("-"):
1453 if line.startswith("-"):
1454 c.hunk[j] = "+" + c.hunk[j][1:]
1454 c.hunk[j] = "+" + c.hunk[j][1:]
1455 elif line.startswith("+"):
1455 elif line.startswith("+"):
1456 c.hunk[j] = "-" + c.hunk[j][1:]
1456 c.hunk[j] = "-" + c.hunk[j][1:]
1457 c.added, c.removed = c.removed, c.added
1457 c.added, c.removed = c.removed, c.added
1458 newhunks.append(c)
1458 newhunks.append(c)
1459 return newhunks
1459 return newhunks
1460
1460
1461 def parsepatch(originalchunks):
1461 def parsepatch(originalchunks):
1462 """patch -> [] of headers -> [] of hunks """
1462 """patch -> [] of headers -> [] of hunks """
1463 class parser(object):
1463 class parser(object):
1464 """patch parsing state machine"""
1464 """patch parsing state machine"""
1465 def __init__(self):
1465 def __init__(self):
1466 self.fromline = 0
1466 self.fromline = 0
1467 self.toline = 0
1467 self.toline = 0
1468 self.proc = ''
1468 self.proc = ''
1469 self.header = None
1469 self.header = None
1470 self.context = []
1470 self.context = []
1471 self.before = []
1471 self.before = []
1472 self.hunk = []
1472 self.hunk = []
1473 self.headers = []
1473 self.headers = []
1474
1474
1475 def addrange(self, limits):
1475 def addrange(self, limits):
1476 fromstart, fromend, tostart, toend, proc = limits
1476 fromstart, fromend, tostart, toend, proc = limits
1477 self.fromline = int(fromstart)
1477 self.fromline = int(fromstart)
1478 self.toline = int(tostart)
1478 self.toline = int(tostart)
1479 self.proc = proc
1479 self.proc = proc
1480
1480
1481 def addcontext(self, context):
1481 def addcontext(self, context):
1482 if self.hunk:
1482 if self.hunk:
1483 h = recordhunk(self.header, self.fromline, self.toline,
1483 h = recordhunk(self.header, self.fromline, self.toline,
1484 self.proc, self.before, self.hunk, context)
1484 self.proc, self.before, self.hunk, context)
1485 self.header.hunks.append(h)
1485 self.header.hunks.append(h)
1486 self.fromline += len(self.before) + h.removed
1486 self.fromline += len(self.before) + h.removed
1487 self.toline += len(self.before) + h.added
1487 self.toline += len(self.before) + h.added
1488 self.before = []
1488 self.before = []
1489 self.hunk = []
1489 self.hunk = []
1490 self.proc = ''
1490 self.proc = ''
1491 self.context = context
1491 self.context = context
1492
1492
1493 def addhunk(self, hunk):
1493 def addhunk(self, hunk):
1494 if self.context:
1494 if self.context:
1495 self.before = self.context
1495 self.before = self.context
1496 self.context = []
1496 self.context = []
1497 self.hunk = hunk
1497 self.hunk = hunk
1498
1498
1499 def newfile(self, hdr):
1499 def newfile(self, hdr):
1500 self.addcontext([])
1500 self.addcontext([])
1501 h = header(hdr)
1501 h = header(hdr)
1502 self.headers.append(h)
1502 self.headers.append(h)
1503 self.header = h
1503 self.header = h
1504
1504
1505 def addother(self, line):
1505 def addother(self, line):
1506 pass # 'other' lines are ignored
1506 pass # 'other' lines are ignored
1507
1507
1508 def finished(self):
1508 def finished(self):
1509 self.addcontext([])
1509 self.addcontext([])
1510 return self.headers
1510 return self.headers
1511
1511
1512 transitions = {
1512 transitions = {
1513 'file': {'context': addcontext,
1513 'file': {'context': addcontext,
1514 'file': newfile,
1514 'file': newfile,
1515 'hunk': addhunk,
1515 'hunk': addhunk,
1516 'range': addrange},
1516 'range': addrange},
1517 'context': {'file': newfile,
1517 'context': {'file': newfile,
1518 'hunk': addhunk,
1518 'hunk': addhunk,
1519 'range': addrange,
1519 'range': addrange,
1520 'other': addother},
1520 'other': addother},
1521 'hunk': {'context': addcontext,
1521 'hunk': {'context': addcontext,
1522 'file': newfile,
1522 'file': newfile,
1523 'range': addrange},
1523 'range': addrange},
1524 'range': {'context': addcontext,
1524 'range': {'context': addcontext,
1525 'hunk': addhunk},
1525 'hunk': addhunk},
1526 'other': {'other': addother},
1526 'other': {'other': addother},
1527 }
1527 }
1528
1528
1529 p = parser()
1529 p = parser()
1530 fp = cStringIO.StringIO()
1530 fp = cStringIO.StringIO()
1531 fp.write(''.join(originalchunks))
1531 fp.write(''.join(originalchunks))
1532 fp.seek(0)
1532 fp.seek(0)
1533
1533
1534 state = 'context'
1534 state = 'context'
1535 for newstate, data in scanpatch(fp):
1535 for newstate, data in scanpatch(fp):
1536 try:
1536 try:
1537 p.transitions[state][newstate](p, data)
1537 p.transitions[state][newstate](p, data)
1538 except KeyError:
1538 except KeyError:
1539 raise PatchError('unhandled transition: %s -> %s' %
1539 raise PatchError('unhandled transition: %s -> %s' %
1540 (state, newstate))
1540 (state, newstate))
1541 state = newstate
1541 state = newstate
1542 del fp
1542 del fp
1543 return p.finished()
1543 return p.finished()
1544
1544
1545 def pathtransform(path, strip, prefix):
1545 def pathtransform(path, strip, prefix):
1546 '''turn a path from a patch into a path suitable for the repository
1546 '''turn a path from a patch into a path suitable for the repository
1547
1547
1548 prefix, if not empty, is expected to be normalized with a / at the end.
1548 prefix, if not empty, is expected to be normalized with a / at the end.
1549
1549
1550 Returns (stripped components, path in repository).
1550 Returns (stripped components, path in repository).
1551
1551
1552 >>> pathtransform('a/b/c', 0, '')
1552 >>> pathtransform('a/b/c', 0, '')
1553 ('', 'a/b/c')
1553 ('', 'a/b/c')
1554 >>> pathtransform(' a/b/c ', 0, '')
1554 >>> pathtransform(' a/b/c ', 0, '')
1555 ('', ' a/b/c')
1555 ('', ' a/b/c')
1556 >>> pathtransform(' a/b/c ', 2, '')
1556 >>> pathtransform(' a/b/c ', 2, '')
1557 ('a/b/', 'c')
1557 ('a/b/', 'c')
1558 >>> pathtransform('a/b/c', 0, 'd/e/')
1558 >>> pathtransform('a/b/c', 0, 'd/e/')
1559 ('', 'd/e/a/b/c')
1559 ('', 'd/e/a/b/c')
1560 >>> pathtransform(' a//b/c ', 2, 'd/e/')
1560 >>> pathtransform(' a//b/c ', 2, 'd/e/')
1561 ('a//b/', 'd/e/c')
1561 ('a//b/', 'd/e/c')
1562 >>> pathtransform('a/b/c', 3, '')
1562 >>> pathtransform('a/b/c', 3, '')
1563 Traceback (most recent call last):
1563 Traceback (most recent call last):
1564 PatchError: unable to strip away 1 of 3 dirs from a/b/c
1564 PatchError: unable to strip away 1 of 3 dirs from a/b/c
1565 '''
1565 '''
1566 pathlen = len(path)
1566 pathlen = len(path)
1567 i = 0
1567 i = 0
1568 if strip == 0:
1568 if strip == 0:
1569 return '', prefix + path.rstrip()
1569 return '', prefix + path.rstrip()
1570 count = strip
1570 count = strip
1571 while count > 0:
1571 while count > 0:
1572 i = path.find('/', i)
1572 i = path.find('/', i)
1573 if i == -1:
1573 if i == -1:
1574 raise PatchError(_("unable to strip away %d of %d dirs from %s") %
1574 raise PatchError(_("unable to strip away %d of %d dirs from %s") %
1575 (count, strip, path))
1575 (count, strip, path))
1576 i += 1
1576 i += 1
1577 # consume '//' in the path
1577 # consume '//' in the path
1578 while i < pathlen - 1 and path[i] == '/':
1578 while i < pathlen - 1 and path[i] == '/':
1579 i += 1
1579 i += 1
1580 count -= 1
1580 count -= 1
1581 return path[:i].lstrip(), prefix + path[i:].rstrip()
1581 return path[:i].lstrip(), prefix + path[i:].rstrip()
1582
1582
1583 def makepatchmeta(backend, afile_orig, bfile_orig, hunk, strip, prefix):
1583 def makepatchmeta(backend, afile_orig, bfile_orig, hunk, strip, prefix):
1584 nulla = afile_orig == "/dev/null"
1584 nulla = afile_orig == "/dev/null"
1585 nullb = bfile_orig == "/dev/null"
1585 nullb = bfile_orig == "/dev/null"
1586 create = nulla and hunk.starta == 0 and hunk.lena == 0
1586 create = nulla and hunk.starta == 0 and hunk.lena == 0
1587 remove = nullb and hunk.startb == 0 and hunk.lenb == 0
1587 remove = nullb and hunk.startb == 0 and hunk.lenb == 0
1588 abase, afile = pathtransform(afile_orig, strip, prefix)
1588 abase, afile = pathtransform(afile_orig, strip, prefix)
1589 gooda = not nulla and backend.exists(afile)
1589 gooda = not nulla and backend.exists(afile)
1590 bbase, bfile = pathtransform(bfile_orig, strip, prefix)
1590 bbase, bfile = pathtransform(bfile_orig, strip, prefix)
1591 if afile == bfile:
1591 if afile == bfile:
1592 goodb = gooda
1592 goodb = gooda
1593 else:
1593 else:
1594 goodb = not nullb and backend.exists(bfile)
1594 goodb = not nullb and backend.exists(bfile)
1595 missing = not goodb and not gooda and not create
1595 missing = not goodb and not gooda and not create
1596
1596
1597 # some diff programs apparently produce patches where the afile is
1597 # some diff programs apparently produce patches where the afile is
1598 # not /dev/null, but afile starts with bfile
1598 # not /dev/null, but afile starts with bfile
1599 abasedir = afile[:afile.rfind('/') + 1]
1599 abasedir = afile[:afile.rfind('/') + 1]
1600 bbasedir = bfile[:bfile.rfind('/') + 1]
1600 bbasedir = bfile[:bfile.rfind('/') + 1]
1601 if (missing and abasedir == bbasedir and afile.startswith(bfile)
1601 if (missing and abasedir == bbasedir and afile.startswith(bfile)
1602 and hunk.starta == 0 and hunk.lena == 0):
1602 and hunk.starta == 0 and hunk.lena == 0):
1603 create = True
1603 create = True
1604 missing = False
1604 missing = False
1605
1605
1606 # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
1606 # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
1607 # diff is between a file and its backup. In this case, the original
1607 # diff is between a file and its backup. In this case, the original
1608 # file should be patched (see original mpatch code).
1608 # file should be patched (see original mpatch code).
1609 isbackup = (abase == bbase and bfile.startswith(afile))
1609 isbackup = (abase == bbase and bfile.startswith(afile))
1610 fname = None
1610 fname = None
1611 if not missing:
1611 if not missing:
1612 if gooda and goodb:
1612 if gooda and goodb:
1613 if isbackup:
1613 if isbackup:
1614 fname = afile
1614 fname = afile
1615 else:
1615 else:
1616 fname = bfile
1616 fname = bfile
1617 elif gooda:
1617 elif gooda:
1618 fname = afile
1618 fname = afile
1619
1619
1620 if not fname:
1620 if not fname:
1621 if not nullb:
1621 if not nullb:
1622 if isbackup:
1622 if isbackup:
1623 fname = afile
1623 fname = afile
1624 else:
1624 else:
1625 fname = bfile
1625 fname = bfile
1626 elif not nulla:
1626 elif not nulla:
1627 fname = afile
1627 fname = afile
1628 else:
1628 else:
1629 raise PatchError(_("undefined source and destination files"))
1629 raise PatchError(_("undefined source and destination files"))
1630
1630
1631 gp = patchmeta(fname)
1631 gp = patchmeta(fname)
1632 if create:
1632 if create:
1633 gp.op = 'ADD'
1633 gp.op = 'ADD'
1634 elif remove:
1634 elif remove:
1635 gp.op = 'DELETE'
1635 gp.op = 'DELETE'
1636 return gp
1636 return gp
1637
1637
1638 def scanpatch(fp):
1638 def scanpatch(fp):
1639 """like patch.iterhunks, but yield different events
1639 """like patch.iterhunks, but yield different events
1640
1640
1641 - ('file', [header_lines + fromfile + tofile])
1641 - ('file', [header_lines + fromfile + tofile])
1642 - ('context', [context_lines])
1642 - ('context', [context_lines])
1643 - ('hunk', [hunk_lines])
1643 - ('hunk', [hunk_lines])
1644 - ('range', (-start,len, +start,len, proc))
1644 - ('range', (-start,len, +start,len, proc))
1645 """
1645 """
1646 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
1646 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
1647 lr = linereader(fp)
1647 lr = linereader(fp)
1648
1648
1649 def scanwhile(first, p):
1649 def scanwhile(first, p):
1650 """scan lr while predicate holds"""
1650 """scan lr while predicate holds"""
1651 lines = [first]
1651 lines = [first]
1652 while True:
1652 while True:
1653 line = lr.readline()
1653 line = lr.readline()
1654 if not line:
1654 if not line:
1655 break
1655 break
1656 if p(line):
1656 if p(line):
1657 lines.append(line)
1657 lines.append(line)
1658 else:
1658 else:
1659 lr.push(line)
1659 lr.push(line)
1660 break
1660 break
1661 return lines
1661 return lines
1662
1662
1663 while True:
1663 while True:
1664 line = lr.readline()
1664 line = lr.readline()
1665 if not line:
1665 if not line:
1666 break
1666 break
1667 if line.startswith('diff --git a/') or line.startswith('diff -r '):
1667 if line.startswith('diff --git a/') or line.startswith('diff -r '):
1668 def notheader(line):
1668 def notheader(line):
1669 s = line.split(None, 1)
1669 s = line.split(None, 1)
1670 return not s or s[0] not in ('---', 'diff')
1670 return not s or s[0] not in ('---', 'diff')
1671 header = scanwhile(line, notheader)
1671 header = scanwhile(line, notheader)
1672 fromfile = lr.readline()
1672 fromfile = lr.readline()
1673 if fromfile.startswith('---'):
1673 if fromfile.startswith('---'):
1674 tofile = lr.readline()
1674 tofile = lr.readline()
1675 header += [fromfile, tofile]
1675 header += [fromfile, tofile]
1676 else:
1676 else:
1677 lr.push(fromfile)
1677 lr.push(fromfile)
1678 yield 'file', header
1678 yield 'file', header
1679 elif line[0] == ' ':
1679 elif line[0] == ' ':
1680 yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
1680 yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
1681 elif line[0] in '-+':
1681 elif line[0] in '-+':
1682 yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
1682 yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
1683 else:
1683 else:
1684 m = lines_re.match(line)
1684 m = lines_re.match(line)
1685 if m:
1685 if m:
1686 yield 'range', m.groups()
1686 yield 'range', m.groups()
1687 else:
1687 else:
1688 yield 'other', line
1688 yield 'other', line
1689
1689
1690 def scangitpatch(lr, firstline):
1690 def scangitpatch(lr, firstline):
1691 """
1691 """
1692 Git patches can emit:
1692 Git patches can emit:
1693 - rename a to b
1693 - rename a to b
1694 - change b
1694 - change b
1695 - copy a to c
1695 - copy a to c
1696 - change c
1696 - change c
1697
1697
1698 We cannot apply this sequence as-is, the renamed 'a' could not be
1698 We cannot apply this sequence as-is, the renamed 'a' could not be
1699 found for it would have been renamed already. And we cannot copy
1699 found for it would have been renamed already. And we cannot copy
1700 from 'b' instead because 'b' would have been changed already. So
1700 from 'b' instead because 'b' would have been changed already. So
1701 we scan the git patch for copy and rename commands so we can
1701 we scan the git patch for copy and rename commands so we can
1702 perform the copies ahead of time.
1702 perform the copies ahead of time.
1703 """
1703 """
1704 pos = 0
1704 pos = 0
1705 try:
1705 try:
1706 pos = lr.fp.tell()
1706 pos = lr.fp.tell()
1707 fp = lr.fp
1707 fp = lr.fp
1708 except IOError:
1708 except IOError:
1709 fp = cStringIO.StringIO(lr.fp.read())
1709 fp = cStringIO.StringIO(lr.fp.read())
1710 gitlr = linereader(fp)
1710 gitlr = linereader(fp)
1711 gitlr.push(firstline)
1711 gitlr.push(firstline)
1712 gitpatches = readgitpatch(gitlr)
1712 gitpatches = readgitpatch(gitlr)
1713 fp.seek(pos)
1713 fp.seek(pos)
1714 return gitpatches
1714 return gitpatches
1715
1715
1716 def iterhunks(fp):
1716 def iterhunks(fp):
1717 """Read a patch and yield the following events:
1717 """Read a patch and yield the following events:
1718 - ("file", afile, bfile, firsthunk): select a new target file.
1718 - ("file", afile, bfile, firsthunk): select a new target file.
1719 - ("hunk", hunk): a new hunk is ready to be applied, follows a
1719 - ("hunk", hunk): a new hunk is ready to be applied, follows a
1720 "file" event.
1720 "file" event.
1721 - ("git", gitchanges): current diff is in git format, gitchanges
1721 - ("git", gitchanges): current diff is in git format, gitchanges
1722 maps filenames to gitpatch records. Unique event.
1722 maps filenames to gitpatch records. Unique event.
1723 """
1723 """
1724 afile = ""
1724 afile = ""
1725 bfile = ""
1725 bfile = ""
1726 state = None
1726 state = None
1727 hunknum = 0
1727 hunknum = 0
1728 emitfile = newfile = False
1728 emitfile = newfile = False
1729 gitpatches = None
1729 gitpatches = None
1730
1730
1731 # our states
1731 # our states
1732 BFILE = 1
1732 BFILE = 1
1733 context = None
1733 context = None
1734 lr = linereader(fp)
1734 lr = linereader(fp)
1735
1735
1736 while True:
1736 while True:
1737 x = lr.readline()
1737 x = lr.readline()
1738 if not x:
1738 if not x:
1739 break
1739 break
1740 if state == BFILE and (
1740 if state == BFILE and (
1741 (not context and x[0] == '@')
1741 (not context and x[0] == '@')
1742 or (context is not False and x.startswith('***************'))
1742 or (context is not False and x.startswith('***************'))
1743 or x.startswith('GIT binary patch')):
1743 or x.startswith('GIT binary patch')):
1744 gp = None
1744 gp = None
1745 if (gitpatches and
1745 if (gitpatches and
1746 gitpatches[-1].ispatching(afile, bfile)):
1746 gitpatches[-1].ispatching(afile, bfile)):
1747 gp = gitpatches.pop()
1747 gp = gitpatches.pop()
1748 if x.startswith('GIT binary patch'):
1748 if x.startswith('GIT binary patch'):
1749 h = binhunk(lr, gp.path)
1749 h = binhunk(lr, gp.path)
1750 else:
1750 else:
1751 if context is None and x.startswith('***************'):
1751 if context is None and x.startswith('***************'):
1752 context = True
1752 context = True
1753 h = hunk(x, hunknum + 1, lr, context)
1753 h = hunk(x, hunknum + 1, lr, context)
1754 hunknum += 1
1754 hunknum += 1
1755 if emitfile:
1755 if emitfile:
1756 emitfile = False
1756 emitfile = False
1757 yield 'file', (afile, bfile, h, gp and gp.copy() or None)
1757 yield 'file', (afile, bfile, h, gp and gp.copy() or None)
1758 yield 'hunk', h
1758 yield 'hunk', h
1759 elif x.startswith('diff --git a/'):
1759 elif x.startswith('diff --git a/'):
1760 m = gitre.match(x.rstrip(' \r\n'))
1760 m = gitre.match(x.rstrip(' \r\n'))
1761 if not m:
1761 if not m:
1762 continue
1762 continue
1763 if gitpatches is None:
1763 if gitpatches is None:
1764 # scan whole input for git metadata
1764 # scan whole input for git metadata
1765 gitpatches = scangitpatch(lr, x)
1765 gitpatches = scangitpatch(lr, x)
1766 yield 'git', [g.copy() for g in gitpatches
1766 yield 'git', [g.copy() for g in gitpatches
1767 if g.op in ('COPY', 'RENAME')]
1767 if g.op in ('COPY', 'RENAME')]
1768 gitpatches.reverse()
1768 gitpatches.reverse()
1769 afile = 'a/' + m.group(1)
1769 afile = 'a/' + m.group(1)
1770 bfile = 'b/' + m.group(2)
1770 bfile = 'b/' + m.group(2)
1771 while gitpatches and not gitpatches[-1].ispatching(afile, bfile):
1771 while gitpatches and not gitpatches[-1].ispatching(afile, bfile):
1772 gp = gitpatches.pop()
1772 gp = gitpatches.pop()
1773 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1773 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1774 if not gitpatches:
1774 if not gitpatches:
1775 raise PatchError(_('failed to synchronize metadata for "%s"')
1775 raise PatchError(_('failed to synchronize metadata for "%s"')
1776 % afile[2:])
1776 % afile[2:])
1777 gp = gitpatches[-1]
1777 gp = gitpatches[-1]
1778 newfile = True
1778 newfile = True
1779 elif x.startswith('---'):
1779 elif x.startswith('---'):
1780 # check for a unified diff
1780 # check for a unified diff
1781 l2 = lr.readline()
1781 l2 = lr.readline()
1782 if not l2.startswith('+++'):
1782 if not l2.startswith('+++'):
1783 lr.push(l2)
1783 lr.push(l2)
1784 continue
1784 continue
1785 newfile = True
1785 newfile = True
1786 context = False
1786 context = False
1787 afile = parsefilename(x)
1787 afile = parsefilename(x)
1788 bfile = parsefilename(l2)
1788 bfile = parsefilename(l2)
1789 elif x.startswith('***'):
1789 elif x.startswith('***'):
1790 # check for a context diff
1790 # check for a context diff
1791 l2 = lr.readline()
1791 l2 = lr.readline()
1792 if not l2.startswith('---'):
1792 if not l2.startswith('---'):
1793 lr.push(l2)
1793 lr.push(l2)
1794 continue
1794 continue
1795 l3 = lr.readline()
1795 l3 = lr.readline()
1796 lr.push(l3)
1796 lr.push(l3)
1797 if not l3.startswith("***************"):
1797 if not l3.startswith("***************"):
1798 lr.push(l2)
1798 lr.push(l2)
1799 continue
1799 continue
1800 newfile = True
1800 newfile = True
1801 context = True
1801 context = True
1802 afile = parsefilename(x)
1802 afile = parsefilename(x)
1803 bfile = parsefilename(l2)
1803 bfile = parsefilename(l2)
1804
1804
1805 if newfile:
1805 if newfile:
1806 newfile = False
1806 newfile = False
1807 emitfile = True
1807 emitfile = True
1808 state = BFILE
1808 state = BFILE
1809 hunknum = 0
1809 hunknum = 0
1810
1810
1811 while gitpatches:
1811 while gitpatches:
1812 gp = gitpatches.pop()
1812 gp = gitpatches.pop()
1813 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1813 yield 'file', ('a/' + gp.path, 'b/' + gp.path, None, gp.copy())
1814
1814
1815 def applybindelta(binchunk, data):
1815 def applybindelta(binchunk, data):
1816 """Apply a binary delta hunk
1816 """Apply a binary delta hunk
1817 The algorithm used is the algorithm from git's patch-delta.c
1817 The algorithm used is the algorithm from git's patch-delta.c
1818 """
1818 """
1819 def deltahead(binchunk):
1819 def deltahead(binchunk):
1820 i = 0
1820 i = 0
1821 for c in binchunk:
1821 for c in binchunk:
1822 i += 1
1822 i += 1
1823 if not (ord(c) & 0x80):
1823 if not (ord(c) & 0x80):
1824 return i
1824 return i
1825 return i
1825 return i
1826 out = ""
1826 out = ""
1827 s = deltahead(binchunk)
1827 s = deltahead(binchunk)
1828 binchunk = binchunk[s:]
1828 binchunk = binchunk[s:]
1829 s = deltahead(binchunk)
1829 s = deltahead(binchunk)
1830 binchunk = binchunk[s:]
1830 binchunk = binchunk[s:]
1831 i = 0
1831 i = 0
1832 while i < len(binchunk):
1832 while i < len(binchunk):
1833 cmd = ord(binchunk[i])
1833 cmd = ord(binchunk[i])
1834 i += 1
1834 i += 1
1835 if (cmd & 0x80):
1835 if (cmd & 0x80):
1836 offset = 0
1836 offset = 0
1837 size = 0
1837 size = 0
1838 if (cmd & 0x01):
1838 if (cmd & 0x01):
1839 offset = ord(binchunk[i])
1839 offset = ord(binchunk[i])
1840 i += 1
1840 i += 1
1841 if (cmd & 0x02):
1841 if (cmd & 0x02):
1842 offset |= ord(binchunk[i]) << 8
1842 offset |= ord(binchunk[i]) << 8
1843 i += 1
1843 i += 1
1844 if (cmd & 0x04):
1844 if (cmd & 0x04):
1845 offset |= ord(binchunk[i]) << 16
1845 offset |= ord(binchunk[i]) << 16
1846 i += 1
1846 i += 1
1847 if (cmd & 0x08):
1847 if (cmd & 0x08):
1848 offset |= ord(binchunk[i]) << 24
1848 offset |= ord(binchunk[i]) << 24
1849 i += 1
1849 i += 1
1850 if (cmd & 0x10):
1850 if (cmd & 0x10):
1851 size = ord(binchunk[i])
1851 size = ord(binchunk[i])
1852 i += 1
1852 i += 1
1853 if (cmd & 0x20):
1853 if (cmd & 0x20):
1854 size |= ord(binchunk[i]) << 8
1854 size |= ord(binchunk[i]) << 8
1855 i += 1
1855 i += 1
1856 if (cmd & 0x40):
1856 if (cmd & 0x40):
1857 size |= ord(binchunk[i]) << 16
1857 size |= ord(binchunk[i]) << 16
1858 i += 1
1858 i += 1
1859 if size == 0:
1859 if size == 0:
1860 size = 0x10000
1860 size = 0x10000
1861 offset_end = offset + size
1861 offset_end = offset + size
1862 out += data[offset:offset_end]
1862 out += data[offset:offset_end]
1863 elif cmd != 0:
1863 elif cmd != 0:
1864 offset_end = i + cmd
1864 offset_end = i + cmd
1865 out += binchunk[i:offset_end]
1865 out += binchunk[i:offset_end]
1866 i += cmd
1866 i += cmd
1867 else:
1867 else:
1868 raise PatchError(_('unexpected delta opcode 0'))
1868 raise PatchError(_('unexpected delta opcode 0'))
1869 return out
1869 return out
1870
1870
1871 def applydiff(ui, fp, backend, store, strip=1, prefix='', eolmode='strict'):
1871 def applydiff(ui, fp, backend, store, strip=1, prefix='', eolmode='strict'):
1872 """Reads a patch from fp and tries to apply it.
1872 """Reads a patch from fp and tries to apply it.
1873
1873
1874 Returns 0 for a clean patch, -1 if any rejects were found and 1 if
1874 Returns 0 for a clean patch, -1 if any rejects were found and 1 if
1875 there was any fuzz.
1875 there was any fuzz.
1876
1876
1877 If 'eolmode' is 'strict', the patch content and patched file are
1877 If 'eolmode' is 'strict', the patch content and patched file are
1878 read in binary mode. Otherwise, line endings are ignored when
1878 read in binary mode. Otherwise, line endings are ignored when
1879 patching then normalized according to 'eolmode'.
1879 patching then normalized according to 'eolmode'.
1880 """
1880 """
1881 return _applydiff(ui, fp, patchfile, backend, store, strip=strip,
1881 return _applydiff(ui, fp, patchfile, backend, store, strip=strip,
1882 prefix=prefix, eolmode=eolmode)
1882 prefix=prefix, eolmode=eolmode)
1883
1883
1884 def _applydiff(ui, fp, patcher, backend, store, strip=1, prefix='',
1884 def _applydiff(ui, fp, patcher, backend, store, strip=1, prefix='',
1885 eolmode='strict'):
1885 eolmode='strict'):
1886
1886
1887 if prefix:
1887 if prefix:
1888 prefix = pathutil.canonpath(backend.repo.root, backend.repo.getcwd(),
1888 prefix = pathutil.canonpath(backend.repo.root, backend.repo.getcwd(),
1889 prefix)
1889 prefix)
1890 if prefix != '':
1890 if prefix != '':
1891 prefix += '/'
1891 prefix += '/'
1892 def pstrip(p):
1892 def pstrip(p):
1893 return pathtransform(p, strip - 1, prefix)[1]
1893 return pathtransform(p, strip - 1, prefix)[1]
1894
1894
1895 rejects = 0
1895 rejects = 0
1896 err = 0
1896 err = 0
1897 current_file = None
1897 current_file = None
1898
1898
1899 for state, values in iterhunks(fp):
1899 for state, values in iterhunks(fp):
1900 if state == 'hunk':
1900 if state == 'hunk':
1901 if not current_file:
1901 if not current_file:
1902 continue
1902 continue
1903 ret = current_file.apply(values)
1903 ret = current_file.apply(values)
1904 if ret > 0:
1904 if ret > 0:
1905 err = 1
1905 err = 1
1906 elif state == 'file':
1906 elif state == 'file':
1907 if current_file:
1907 if current_file:
1908 rejects += current_file.close()
1908 rejects += current_file.close()
1909 current_file = None
1909 current_file = None
1910 afile, bfile, first_hunk, gp = values
1910 afile, bfile, first_hunk, gp = values
1911 if gp:
1911 if gp:
1912 gp.path = pstrip(gp.path)
1912 gp.path = pstrip(gp.path)
1913 if gp.oldpath:
1913 if gp.oldpath:
1914 gp.oldpath = pstrip(gp.oldpath)
1914 gp.oldpath = pstrip(gp.oldpath)
1915 else:
1915 else:
1916 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
1916 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
1917 prefix)
1917 prefix)
1918 if gp.op == 'RENAME':
1918 if gp.op == 'RENAME':
1919 backend.unlink(gp.oldpath)
1919 backend.unlink(gp.oldpath)
1920 if not first_hunk:
1920 if not first_hunk:
1921 if gp.op == 'DELETE':
1921 if gp.op == 'DELETE':
1922 backend.unlink(gp.path)
1922 backend.unlink(gp.path)
1923 continue
1923 continue
1924 data, mode = None, None
1924 data, mode = None, None
1925 if gp.op in ('RENAME', 'COPY'):
1925 if gp.op in ('RENAME', 'COPY'):
1926 data, mode = store.getfile(gp.oldpath)[:2]
1926 data, mode = store.getfile(gp.oldpath)[:2]
1927 # FIXME: failing getfile has never been handled here
1927 # FIXME: failing getfile has never been handled here
1928 assert data is not None
1928 assert data is not None
1929 if gp.mode:
1929 if gp.mode:
1930 mode = gp.mode
1930 mode = gp.mode
1931 if gp.op == 'ADD':
1931 if gp.op == 'ADD':
1932 # Added files without content have no hunk and
1932 # Added files without content have no hunk and
1933 # must be created
1933 # must be created
1934 data = ''
1934 data = ''
1935 if data or mode:
1935 if data or mode:
1936 if (gp.op in ('ADD', 'RENAME', 'COPY')
1936 if (gp.op in ('ADD', 'RENAME', 'COPY')
1937 and backend.exists(gp.path)):
1937 and backend.exists(gp.path)):
1938 raise PatchError(_("cannot create %s: destination "
1938 raise PatchError(_("cannot create %s: destination "
1939 "already exists") % gp.path)
1939 "already exists") % gp.path)
1940 backend.setfile(gp.path, data, mode, gp.oldpath)
1940 backend.setfile(gp.path, data, mode, gp.oldpath)
1941 continue
1941 continue
1942 try:
1942 try:
1943 current_file = patcher(ui, gp, backend, store,
1943 current_file = patcher(ui, gp, backend, store,
1944 eolmode=eolmode)
1944 eolmode=eolmode)
1945 except PatchError, inst:
1945 except PatchError, inst:
1946 ui.warn(str(inst) + '\n')
1946 ui.warn(str(inst) + '\n')
1947 current_file = None
1947 current_file = None
1948 rejects += 1
1948 rejects += 1
1949 continue
1949 continue
1950 elif state == 'git':
1950 elif state == 'git':
1951 for gp in values:
1951 for gp in values:
1952 path = pstrip(gp.oldpath)
1952 path = pstrip(gp.oldpath)
1953 data, mode = backend.getfile(path)
1953 data, mode = backend.getfile(path)
1954 if data is None:
1954 if data is None:
1955 # The error ignored here will trigger a getfile()
1955 # The error ignored here will trigger a getfile()
1956 # error in a place more appropriate for error
1956 # error in a place more appropriate for error
1957 # handling, and will not interrupt the patching
1957 # handling, and will not interrupt the patching
1958 # process.
1958 # process.
1959 pass
1959 pass
1960 else:
1960 else:
1961 store.setfile(path, data, mode)
1961 store.setfile(path, data, mode)
1962 else:
1962 else:
1963 raise util.Abort(_('unsupported parser state: %s') % state)
1963 raise util.Abort(_('unsupported parser state: %s') % state)
1964
1964
1965 if current_file:
1965 if current_file:
1966 rejects += current_file.close()
1966 rejects += current_file.close()
1967
1967
1968 if rejects:
1968 if rejects:
1969 return -1
1969 return -1
1970 return err
1970 return err
1971
1971
1972 def _externalpatch(ui, repo, patcher, patchname, strip, files,
1972 def _externalpatch(ui, repo, patcher, patchname, strip, files,
1973 similarity):
1973 similarity):
1974 """use <patcher> to apply <patchname> to the working directory.
1974 """use <patcher> to apply <patchname> to the working directory.
1975 returns whether patch was applied with fuzz factor."""
1975 returns whether patch was applied with fuzz factor."""
1976
1976
1977 fuzz = False
1977 fuzz = False
1978 args = []
1978 args = []
1979 cwd = repo.root
1979 cwd = repo.root
1980 if cwd:
1980 if cwd:
1981 args.append('-d %s' % util.shellquote(cwd))
1981 args.append('-d %s' % util.shellquote(cwd))
1982 fp = util.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
1982 fp = util.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
1983 util.shellquote(patchname)))
1983 util.shellquote(patchname)))
1984 try:
1984 try:
1985 for line in fp:
1985 for line in fp:
1986 line = line.rstrip()
1986 line = line.rstrip()
1987 ui.note(line + '\n')
1987 ui.note(line + '\n')
1988 if line.startswith('patching file '):
1988 if line.startswith('patching file '):
1989 pf = util.parsepatchoutput(line)
1989 pf = util.parsepatchoutput(line)
1990 printed_file = False
1990 printed_file = False
1991 files.add(pf)
1991 files.add(pf)
1992 elif line.find('with fuzz') >= 0:
1992 elif line.find('with fuzz') >= 0:
1993 fuzz = True
1993 fuzz = True
1994 if not printed_file:
1994 if not printed_file:
1995 ui.warn(pf + '\n')
1995 ui.warn(pf + '\n')
1996 printed_file = True
1996 printed_file = True
1997 ui.warn(line + '\n')
1997 ui.warn(line + '\n')
1998 elif line.find('saving rejects to file') >= 0:
1998 elif line.find('saving rejects to file') >= 0:
1999 ui.warn(line + '\n')
1999 ui.warn(line + '\n')
2000 elif line.find('FAILED') >= 0:
2000 elif line.find('FAILED') >= 0:
2001 if not printed_file:
2001 if not printed_file:
2002 ui.warn(pf + '\n')
2002 ui.warn(pf + '\n')
2003 printed_file = True
2003 printed_file = True
2004 ui.warn(line + '\n')
2004 ui.warn(line + '\n')
2005 finally:
2005 finally:
2006 if files:
2006 if files:
2007 scmutil.marktouched(repo, files, similarity)
2007 scmutil.marktouched(repo, files, similarity)
2008 code = fp.close()
2008 code = fp.close()
2009 if code:
2009 if code:
2010 raise PatchError(_("patch command failed: %s") %
2010 raise PatchError(_("patch command failed: %s") %
2011 util.explainexit(code)[0])
2011 util.explainexit(code)[0])
2012 return fuzz
2012 return fuzz
2013
2013
2014 def patchbackend(ui, backend, patchobj, strip, prefix, files=None,
2014 def patchbackend(ui, backend, patchobj, strip, prefix, files=None,
2015 eolmode='strict'):
2015 eolmode='strict'):
2016 if files is None:
2016 if files is None:
2017 files = set()
2017 files = set()
2018 if eolmode is None:
2018 if eolmode is None:
2019 eolmode = ui.config('patch', 'eol', 'strict')
2019 eolmode = ui.config('patch', 'eol', 'strict')
2020 if eolmode.lower() not in eolmodes:
2020 if eolmode.lower() not in eolmodes:
2021 raise util.Abort(_('unsupported line endings type: %s') % eolmode)
2021 raise util.Abort(_('unsupported line endings type: %s') % eolmode)
2022 eolmode = eolmode.lower()
2022 eolmode = eolmode.lower()
2023
2023
2024 store = filestore()
2024 store = filestore()
2025 try:
2025 try:
2026 fp = open(patchobj, 'rb')
2026 fp = open(patchobj, 'rb')
2027 except TypeError:
2027 except TypeError:
2028 fp = patchobj
2028 fp = patchobj
2029 try:
2029 try:
2030 ret = applydiff(ui, fp, backend, store, strip=strip, prefix=prefix,
2030 ret = applydiff(ui, fp, backend, store, strip=strip, prefix=prefix,
2031 eolmode=eolmode)
2031 eolmode=eolmode)
2032 finally:
2032 finally:
2033 if fp != patchobj:
2033 if fp != patchobj:
2034 fp.close()
2034 fp.close()
2035 files.update(backend.close())
2035 files.update(backend.close())
2036 store.close()
2036 store.close()
2037 if ret < 0:
2037 if ret < 0:
2038 raise PatchError(_('patch failed to apply'))
2038 raise PatchError(_('patch failed to apply'))
2039 return ret > 0
2039 return ret > 0
2040
2040
2041 def internalpatch(ui, repo, patchobj, strip, prefix='', files=None,
2041 def internalpatch(ui, repo, patchobj, strip, prefix='', files=None,
2042 eolmode='strict', similarity=0):
2042 eolmode='strict', similarity=0):
2043 """use builtin patch to apply <patchobj> to the working directory.
2043 """use builtin patch to apply <patchobj> to the working directory.
2044 returns whether patch was applied with fuzz factor."""
2044 returns whether patch was applied with fuzz factor."""
2045 backend = workingbackend(ui, repo, similarity)
2045 backend = workingbackend(ui, repo, similarity)
2046 return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
2046 return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
2047
2047
2048 def patchrepo(ui, repo, ctx, store, patchobj, strip, prefix, files=None,
2048 def patchrepo(ui, repo, ctx, store, patchobj, strip, prefix, files=None,
2049 eolmode='strict'):
2049 eolmode='strict'):
2050 backend = repobackend(ui, repo, ctx, store)
2050 backend = repobackend(ui, repo, ctx, store)
2051 return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
2051 return patchbackend(ui, backend, patchobj, strip, prefix, files, eolmode)
2052
2052
2053 def patch(ui, repo, patchname, strip=1, prefix='', files=None, eolmode='strict',
2053 def patch(ui, repo, patchname, strip=1, prefix='', files=None, eolmode='strict',
2054 similarity=0):
2054 similarity=0):
2055 """Apply <patchname> to the working directory.
2055 """Apply <patchname> to the working directory.
2056
2056
2057 'eolmode' specifies how end of lines should be handled. It can be:
2057 'eolmode' specifies how end of lines should be handled. It can be:
2058 - 'strict': inputs are read in binary mode, EOLs are preserved
2058 - 'strict': inputs are read in binary mode, EOLs are preserved
2059 - 'crlf': EOLs are ignored when patching and reset to CRLF
2059 - 'crlf': EOLs are ignored when patching and reset to CRLF
2060 - 'lf': EOLs are ignored when patching and reset to LF
2060 - 'lf': EOLs are ignored when patching and reset to LF
2061 - None: get it from user settings, default to 'strict'
2061 - None: get it from user settings, default to 'strict'
2062 'eolmode' is ignored when using an external patcher program.
2062 'eolmode' is ignored when using an external patcher program.
2063
2063
2064 Returns whether patch was applied with fuzz factor.
2064 Returns whether patch was applied with fuzz factor.
2065 """
2065 """
2066 patcher = ui.config('ui', 'patch')
2066 patcher = ui.config('ui', 'patch')
2067 if files is None:
2067 if files is None:
2068 files = set()
2068 files = set()
2069 if patcher:
2069 if patcher:
2070 return _externalpatch(ui, repo, patcher, patchname, strip,
2070 return _externalpatch(ui, repo, patcher, patchname, strip,
2071 files, similarity)
2071 files, similarity)
2072 return internalpatch(ui, repo, patchname, strip, prefix, files, eolmode,
2072 return internalpatch(ui, repo, patchname, strip, prefix, files, eolmode,
2073 similarity)
2073 similarity)
2074
2074
2075 def changedfiles(ui, repo, patchpath, strip=1):
2075 def changedfiles(ui, repo, patchpath, strip=1):
2076 backend = fsbackend(ui, repo.root)
2076 backend = fsbackend(ui, repo.root)
2077 fp = open(patchpath, 'rb')
2077 fp = open(patchpath, 'rb')
2078 try:
2078 try:
2079 changed = set()
2079 changed = set()
2080 for state, values in iterhunks(fp):
2080 for state, values in iterhunks(fp):
2081 if state == 'file':
2081 if state == 'file':
2082 afile, bfile, first_hunk, gp = values
2082 afile, bfile, first_hunk, gp = values
2083 if gp:
2083 if gp:
2084 gp.path = pathtransform(gp.path, strip - 1, '')[1]
2084 gp.path = pathtransform(gp.path, strip - 1, '')[1]
2085 if gp.oldpath:
2085 if gp.oldpath:
2086 gp.oldpath = pathtransform(gp.oldpath, strip - 1, '')[1]
2086 gp.oldpath = pathtransform(gp.oldpath, strip - 1, '')[1]
2087 else:
2087 else:
2088 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
2088 gp = makepatchmeta(backend, afile, bfile, first_hunk, strip,
2089 '')
2089 '')
2090 changed.add(gp.path)
2090 changed.add(gp.path)
2091 if gp.op == 'RENAME':
2091 if gp.op == 'RENAME':
2092 changed.add(gp.oldpath)
2092 changed.add(gp.oldpath)
2093 elif state not in ('hunk', 'git'):
2093 elif state not in ('hunk', 'git'):
2094 raise util.Abort(_('unsupported parser state: %s') % state)
2094 raise util.Abort(_('unsupported parser state: %s') % state)
2095 return changed
2095 return changed
2096 finally:
2096 finally:
2097 fp.close()
2097 fp.close()
2098
2098
2099 class GitDiffRequired(Exception):
2099 class GitDiffRequired(Exception):
2100 pass
2100 pass
2101
2101
2102 def diffallopts(ui, opts=None, untrusted=False, section='diff'):
2102 def diffallopts(ui, opts=None, untrusted=False, section='diff'):
2103 '''return diffopts with all features supported and parsed'''
2103 '''return diffopts with all features supported and parsed'''
2104 return difffeatureopts(ui, opts=opts, untrusted=untrusted, section=section,
2104 return difffeatureopts(ui, opts=opts, untrusted=untrusted, section=section,
2105 git=True, whitespace=True, formatchanging=True)
2105 git=True, whitespace=True, formatchanging=True)
2106
2106
2107 diffopts = diffallopts
2107 diffopts = diffallopts
2108
2108
2109 def difffeatureopts(ui, opts=None, untrusted=False, section='diff', git=False,
2109 def difffeatureopts(ui, opts=None, untrusted=False, section='diff', git=False,
2110 whitespace=False, formatchanging=False):
2110 whitespace=False, formatchanging=False):
2111 '''return diffopts with only opted-in features parsed
2111 '''return diffopts with only opted-in features parsed
2112
2112
2113 Features:
2113 Features:
2114 - git: git-style diffs
2114 - git: git-style diffs
2115 - whitespace: whitespace options like ignoreblanklines and ignorews
2115 - whitespace: whitespace options like ignoreblanklines and ignorews
2116 - formatchanging: options that will likely break or cause correctness issues
2116 - formatchanging: options that will likely break or cause correctness issues
2117 with most diff parsers
2117 with most diff parsers
2118 '''
2118 '''
2119 def get(key, name=None, getter=ui.configbool, forceplain=None):
2119 def get(key, name=None, getter=ui.configbool, forceplain=None):
2120 if opts:
2120 if opts:
2121 v = opts.get(key)
2121 v = opts.get(key)
2122 if v:
2122 if v:
2123 return v
2123 return v
2124 if forceplain is not None and ui.plain():
2124 if forceplain is not None and ui.plain():
2125 return forceplain
2125 return forceplain
2126 return getter(section, name or key, None, untrusted=untrusted)
2126 return getter(section, name or key, None, untrusted=untrusted)
2127
2127
2128 # core options, expected to be understood by every diff parser
2128 # core options, expected to be understood by every diff parser
2129 buildopts = {
2129 buildopts = {
2130 'nodates': get('nodates'),
2130 'nodates': get('nodates'),
2131 'showfunc': get('show_function', 'showfunc'),
2131 'showfunc': get('show_function', 'showfunc'),
2132 'context': get('unified', getter=ui.config),
2132 'context': get('unified', getter=ui.config),
2133 }
2133 }
2134
2134
2135 if git:
2135 if git:
2136 buildopts['git'] = get('git')
2136 buildopts['git'] = get('git')
2137 if whitespace:
2137 if whitespace:
2138 buildopts['ignorews'] = get('ignore_all_space', 'ignorews')
2138 buildopts['ignorews'] = get('ignore_all_space', 'ignorews')
2139 buildopts['ignorewsamount'] = get('ignore_space_change',
2139 buildopts['ignorewsamount'] = get('ignore_space_change',
2140 'ignorewsamount')
2140 'ignorewsamount')
2141 buildopts['ignoreblanklines'] = get('ignore_blank_lines',
2141 buildopts['ignoreblanklines'] = get('ignore_blank_lines',
2142 'ignoreblanklines')
2142 'ignoreblanklines')
2143 if formatchanging:
2143 if formatchanging:
2144 buildopts['text'] = opts and opts.get('text')
2144 buildopts['text'] = opts and opts.get('text')
2145 buildopts['nobinary'] = get('nobinary')
2145 buildopts['nobinary'] = get('nobinary')
2146 buildopts['noprefix'] = get('noprefix', forceplain=False)
2146 buildopts['noprefix'] = get('noprefix', forceplain=False)
2147
2147
2148 return mdiff.diffopts(**buildopts)
2148 return mdiff.diffopts(**buildopts)
2149
2149
2150 def diff(repo, node1=None, node2=None, match=None, changes=None, opts=None,
2150 def diff(repo, node1=None, node2=None, match=None, changes=None, opts=None,
2151 losedatafn=None, prefix='', relroot=''):
2151 losedatafn=None, prefix='', relroot=''):
2152 '''yields diff of changes to files between two nodes, or node and
2152 '''yields diff of changes to files between two nodes, or node and
2153 working directory.
2153 working directory.
2154
2154
2155 if node1 is None, use first dirstate parent instead.
2155 if node1 is None, use first dirstate parent instead.
2156 if node2 is None, compare node1 with working directory.
2156 if node2 is None, compare node1 with working directory.
2157
2157
2158 losedatafn(**kwarg) is a callable run when opts.upgrade=True and
2158 losedatafn(**kwarg) is a callable run when opts.upgrade=True and
2159 every time some change cannot be represented with the current
2159 every time some change cannot be represented with the current
2160 patch format. Return False to upgrade to git patch format, True to
2160 patch format. Return False to upgrade to git patch format, True to
2161 accept the loss or raise an exception to abort the diff. It is
2161 accept the loss or raise an exception to abort the diff. It is
2162 called with the name of current file being diffed as 'fn'. If set
2162 called with the name of current file being diffed as 'fn'. If set
2163 to None, patches will always be upgraded to git format when
2163 to None, patches will always be upgraded to git format when
2164 necessary.
2164 necessary.
2165
2165
2166 prefix is a filename prefix that is prepended to all filenames on
2166 prefix is a filename prefix that is prepended to all filenames on
2167 display (used for subrepos).
2167 display (used for subrepos).
2168
2168
2169 relroot, if not empty, must be normalized with a trailing /. Any match
2169 relroot, if not empty, must be normalized with a trailing /. Any match
2170 patterns that fall outside it will be ignored.'''
2170 patterns that fall outside it will be ignored.'''
2171
2171
2172 if opts is None:
2172 if opts is None:
2173 opts = mdiff.defaultopts
2173 opts = mdiff.defaultopts
2174
2174
2175 if not node1 and not node2:
2175 if not node1 and not node2:
2176 node1 = repo.dirstate.p1()
2176 node1 = repo.dirstate.p1()
2177
2177
2178 def lrugetfilectx():
2178 def lrugetfilectx():
2179 cache = {}
2179 cache = {}
2180 order = collections.deque()
2180 order = collections.deque()
2181 def getfilectx(f, ctx):
2181 def getfilectx(f, ctx):
2182 fctx = ctx.filectx(f, filelog=cache.get(f))
2182 fctx = ctx.filectx(f, filelog=cache.get(f))
2183 if f not in cache:
2183 if f not in cache:
2184 if len(cache) > 20:
2184 if len(cache) > 20:
2185 del cache[order.popleft()]
2185 del cache[order.popleft()]
2186 cache[f] = fctx.filelog()
2186 cache[f] = fctx.filelog()
2187 else:
2187 else:
2188 order.remove(f)
2188 order.remove(f)
2189 order.append(f)
2189 order.append(f)
2190 return fctx
2190 return fctx
2191 return getfilectx
2191 return getfilectx
2192 getfilectx = lrugetfilectx()
2192 getfilectx = lrugetfilectx()
2193
2193
2194 ctx1 = repo[node1]
2194 ctx1 = repo[node1]
2195 ctx2 = repo[node2]
2195 ctx2 = repo[node2]
2196
2196
2197 relfiltered = False
2197 relfiltered = False
2198 if relroot != '' and match.always():
2198 if relroot != '' and match.always():
2199 # as a special case, create a new matcher with just the relroot
2199 # as a special case, create a new matcher with just the relroot
2200 pats = [relroot]
2200 pats = [relroot]
2201 match = scmutil.match(ctx2, pats, default='path')
2201 match = scmutil.match(ctx2, pats, default='path')
2202 relfiltered = True
2202 relfiltered = True
2203
2203
2204 if not changes:
2204 if not changes:
2205 changes = repo.status(ctx1, ctx2, match=match)
2205 changes = repo.status(ctx1, ctx2, match=match)
2206 modified, added, removed = changes[:3]
2206 modified, added, removed = changes[:3]
2207
2207
2208 if not modified and not added and not removed:
2208 if not modified and not added and not removed:
2209 return []
2209 return []
2210
2210
2211 if repo.ui.debugflag:
2211 if repo.ui.debugflag:
2212 hexfunc = hex
2212 hexfunc = hex
2213 else:
2213 else:
2214 hexfunc = short
2214 hexfunc = short
2215 revs = [hexfunc(node) for node in [ctx1.node(), ctx2.node()] if node]
2215 revs = [hexfunc(node) for node in [ctx1.node(), ctx2.node()] if node]
2216
2216
2217 copy = {}
2217 copy = {}
2218 if opts.git or opts.upgrade:
2218 if opts.git or opts.upgrade:
2219 copy = copies.pathcopies(ctx1, ctx2, match=match)
2219 copy = copies.pathcopies(ctx1, ctx2, match=match)
2220
2220
2221 if relroot is not None:
2221 if relroot is not None:
2222 if not relfiltered:
2222 if not relfiltered:
2223 # XXX this would ideally be done in the matcher, but that is
2223 # XXX this would ideally be done in the matcher, but that is
2224 # generally meant to 'or' patterns, not 'and' them. In this case we
2224 # generally meant to 'or' patterns, not 'and' them. In this case we
2225 # need to 'and' all the patterns from the matcher with relroot.
2225 # need to 'and' all the patterns from the matcher with relroot.
2226 def filterrel(l):
2226 def filterrel(l):
2227 return [f for f in l if f.startswith(relroot)]
2227 return [f for f in l if f.startswith(relroot)]
2228 modified = filterrel(modified)
2228 modified = filterrel(modified)
2229 added = filterrel(added)
2229 added = filterrel(added)
2230 removed = filterrel(removed)
2230 removed = filterrel(removed)
2231 relfiltered = True
2231 relfiltered = True
2232 # filter out copies where either side isn't inside the relative root
2232 # filter out copies where either side isn't inside the relative root
2233 copy = dict(((dst, src) for (dst, src) in copy.iteritems()
2233 copy = dict(((dst, src) for (dst, src) in copy.iteritems()
2234 if dst.startswith(relroot)
2234 if dst.startswith(relroot)
2235 and src.startswith(relroot)))
2235 and src.startswith(relroot)))
2236
2236
2237 def difffn(opts, losedata):
2237 def difffn(opts, losedata):
2238 return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2238 return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2239 copy, getfilectx, opts, losedata, prefix, relroot)
2239 copy, getfilectx, opts, losedata, prefix, relroot)
2240 if opts.upgrade and not opts.git:
2240 if opts.upgrade and not opts.git:
2241 try:
2241 try:
2242 def losedata(fn):
2242 def losedata(fn):
2243 if not losedatafn or not losedatafn(fn=fn):
2243 if not losedatafn or not losedatafn(fn=fn):
2244 raise GitDiffRequired
2244 raise GitDiffRequired
2245 # Buffer the whole output until we are sure it can be generated
2245 # Buffer the whole output until we are sure it can be generated
2246 return list(difffn(opts.copy(git=False), losedata))
2246 return list(difffn(opts.copy(git=False), losedata))
2247 except GitDiffRequired:
2247 except GitDiffRequired:
2248 return difffn(opts.copy(git=True), None)
2248 return difffn(opts.copy(git=True), None)
2249 else:
2249 else:
2250 return difffn(opts, None)
2250 return difffn(opts, None)
2251
2251
2252 def difflabel(func, *args, **kw):
2252 def difflabel(func, *args, **kw):
2253 '''yields 2-tuples of (output, label) based on the output of func()'''
2253 '''yields 2-tuples of (output, label) based on the output of func()'''
2254 headprefixes = [('diff', 'diff.diffline'),
2254 headprefixes = [('diff', 'diff.diffline'),
2255 ('copy', 'diff.extended'),
2255 ('copy', 'diff.extended'),
2256 ('rename', 'diff.extended'),
2256 ('rename', 'diff.extended'),
2257 ('old', 'diff.extended'),
2257 ('old', 'diff.extended'),
2258 ('new', 'diff.extended'),
2258 ('new', 'diff.extended'),
2259 ('deleted', 'diff.extended'),
2259 ('deleted', 'diff.extended'),
2260 ('---', 'diff.file_a'),
2260 ('---', 'diff.file_a'),
2261 ('+++', 'diff.file_b')]
2261 ('+++', 'diff.file_b')]
2262 textprefixes = [('@', 'diff.hunk'),
2262 textprefixes = [('@', 'diff.hunk'),
2263 ('-', 'diff.deleted'),
2263 ('-', 'diff.deleted'),
2264 ('+', 'diff.inserted')]
2264 ('+', 'diff.inserted')]
2265 head = False
2265 head = False
2266 for chunk in func(*args, **kw):
2266 for chunk in func(*args, **kw):
2267 lines = chunk.split('\n')
2267 lines = chunk.split('\n')
2268 for i, line in enumerate(lines):
2268 for i, line in enumerate(lines):
2269 if i != 0:
2269 if i != 0:
2270 yield ('\n', '')
2270 yield ('\n', '')
2271 if head:
2271 if head:
2272 if line.startswith('@'):
2272 if line.startswith('@'):
2273 head = False
2273 head = False
2274 else:
2274 else:
2275 if line and line[0] not in ' +-@\\':
2275 if line and line[0] not in ' +-@\\':
2276 head = True
2276 head = True
2277 stripline = line
2277 stripline = line
2278 diffline = False
2278 diffline = False
2279 if not head and line and line[0] in '+-':
2279 if not head and line and line[0] in '+-':
2280 # highlight tabs and trailing whitespace, but only in
2280 # highlight tabs and trailing whitespace, but only in
2281 # changed lines
2281 # changed lines
2282 stripline = line.rstrip()
2282 stripline = line.rstrip()
2283 diffline = True
2283 diffline = True
2284
2284
2285 prefixes = textprefixes
2285 prefixes = textprefixes
2286 if head:
2286 if head:
2287 prefixes = headprefixes
2287 prefixes = headprefixes
2288 for prefix, label in prefixes:
2288 for prefix, label in prefixes:
2289 if stripline.startswith(prefix):
2289 if stripline.startswith(prefix):
2290 if diffline:
2290 if diffline:
2291 for token in tabsplitter.findall(stripline):
2291 for token in tabsplitter.findall(stripline):
2292 if '\t' == token[0]:
2292 if '\t' == token[0]:
2293 yield (token, 'diff.tab')
2293 yield (token, 'diff.tab')
2294 else:
2294 else:
2295 yield (token, label)
2295 yield (token, label)
2296 else:
2296 else:
2297 yield (stripline, label)
2297 yield (stripline, label)
2298 break
2298 break
2299 else:
2299 else:
2300 yield (line, '')
2300 yield (line, '')
2301 if line != stripline:
2301 if line != stripline:
2302 yield (line[len(stripline):], 'diff.trailingwhitespace')
2302 yield (line[len(stripline):], 'diff.trailingwhitespace')
2303
2303
2304 def diffui(*args, **kw):
2304 def diffui(*args, **kw):
2305 '''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
2305 '''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
2306 return difflabel(diff, *args, **kw)
2306 return difflabel(diff, *args, **kw)
2307
2307
2308 def _filepairs(ctx1, modified, added, removed, copy, opts):
2308 def _filepairs(ctx1, modified, added, removed, copy, opts):
2309 '''generates tuples (f1, f2, copyop), where f1 is the name of the file
2309 '''generates tuples (f1, f2, copyop), where f1 is the name of the file
2310 before and f2 is the the name after. For added files, f1 will be None,
2310 before and f2 is the the name after. For added files, f1 will be None,
2311 and for removed files, f2 will be None. copyop may be set to None, 'copy'
2311 and for removed files, f2 will be None. copyop may be set to None, 'copy'
2312 or 'rename' (the latter two only if opts.git is set).'''
2312 or 'rename' (the latter two only if opts.git is set).'''
2313 gone = set()
2313 gone = set()
2314
2314
2315 copyto = dict([(v, k) for k, v in copy.items()])
2315 copyto = dict([(v, k) for k, v in copy.items()])
2316
2316
2317 addedset, removedset = set(added), set(removed)
2317 addedset, removedset = set(added), set(removed)
2318 # Fix up added, since merged-in additions appear as
2318 # Fix up added, since merged-in additions appear as
2319 # modifications during merges
2319 # modifications during merges
2320 for f in modified:
2320 for f in modified:
2321 if f not in ctx1:
2321 if f not in ctx1:
2322 addedset.add(f)
2322 addedset.add(f)
2323
2323
2324 for f in sorted(modified + added + removed):
2324 for f in sorted(modified + added + removed):
2325 copyop = None
2325 copyop = None
2326 f1, f2 = f, f
2326 f1, f2 = f, f
2327 if f in addedset:
2327 if f in addedset:
2328 f1 = None
2328 f1 = None
2329 if f in copy:
2329 if f in copy:
2330 if opts.git:
2330 if opts.git:
2331 f1 = copy[f]
2331 f1 = copy[f]
2332 if f1 in removedset and f1 not in gone:
2332 if f1 in removedset and f1 not in gone:
2333 copyop = 'rename'
2333 copyop = 'rename'
2334 gone.add(f1)
2334 gone.add(f1)
2335 else:
2335 else:
2336 copyop = 'copy'
2336 copyop = 'copy'
2337 elif f in removedset:
2337 elif f in removedset:
2338 f2 = None
2338 f2 = None
2339 if opts.git:
2339 if opts.git:
2340 # have we already reported a copy above?
2340 # have we already reported a copy above?
2341 if (f in copyto and copyto[f] in addedset
2341 if (f in copyto and copyto[f] in addedset
2342 and copy[copyto[f]] == f):
2342 and copy[copyto[f]] == f):
2343 continue
2343 continue
2344 yield f1, f2, copyop
2344 yield f1, f2, copyop
2345
2345
2346 def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2346 def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2347 copy, getfilectx, opts, losedatafn, prefix, relroot):
2347 copy, getfilectx, opts, losedatafn, prefix, relroot):
2348 '''given input data, generate a diff and yield it in blocks
2348 '''given input data, generate a diff and yield it in blocks
2349
2349
2350 If generating a diff would lose data like flags or binary data and
2350 If generating a diff would lose data like flags or binary data and
2351 losedatafn is not None, it will be called.
2351 losedatafn is not None, it will be called.
2352
2352
2353 relroot is removed and prefix is added to every path in the diff output.
2353 relroot is removed and prefix is added to every path in the diff output.
2354
2354
2355 If relroot is not empty, this function expects every path in modified,
2355 If relroot is not empty, this function expects every path in modified,
2356 added, removed and copy to start with it.'''
2356 added, removed and copy to start with it.'''
2357
2357
2358 def gitindex(text):
2358 def gitindex(text):
2359 if not text:
2359 if not text:
2360 text = ""
2360 text = ""
2361 l = len(text)
2361 l = len(text)
2362 s = util.sha1('blob %d\0' % l)
2362 s = util.sha1('blob %d\0' % l)
2363 s.update(text)
2363 s.update(text)
2364 return s.hexdigest()
2364 return s.hexdigest()
2365
2365
2366 if opts.noprefix:
2366 if opts.noprefix:
2367 aprefix = bprefix = ''
2367 aprefix = bprefix = ''
2368 else:
2368 else:
2369 aprefix = 'a/'
2369 aprefix = 'a/'
2370 bprefix = 'b/'
2370 bprefix = 'b/'
2371
2371
2372 def diffline(f, revs):
2372 def diffline(f, revs):
2373 revinfo = ' '.join(["-r %s" % rev for rev in revs])
2373 revinfo = ' '.join(["-r %s" % rev for rev in revs])
2374 return 'diff %s %s' % (revinfo, f)
2374 return 'diff %s %s' % (revinfo, f)
2375
2375
2376 date1 = util.datestr(ctx1.date())
2376 date1 = util.datestr(ctx1.date())
2377 date2 = util.datestr(ctx2.date())
2377 date2 = util.datestr(ctx2.date())
2378
2378
2379 gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2379 gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2380
2380
2381 if relroot != '' and (repo.ui.configbool('devel', 'all')
2381 if relroot != '' and (repo.ui.configbool('devel', 'all')
2382 or repo.ui.configbool('devel', 'check-relroot')):
2382 or repo.ui.configbool('devel', 'check-relroot')):
2383 for f in modified + added + removed + copy.keys() + copy.values():
2383 for f in modified + added + removed + copy.keys() + copy.values():
2384 if f is not None and not f.startswith(relroot):
2384 if f is not None and not f.startswith(relroot):
2385 raise AssertionError(
2385 raise AssertionError(
2386 "file %s doesn't start with relroot %s" % (f, relroot))
2386 "file %s doesn't start with relroot %s" % (f, relroot))
2387
2387
2388 for f1, f2, copyop in _filepairs(
2388 for f1, f2, copyop in _filepairs(
2389 ctx1, modified, added, removed, copy, opts):
2389 ctx1, modified, added, removed, copy, opts):
2390 content1 = None
2390 content1 = None
2391 content2 = None
2391 content2 = None
2392 flag1 = None
2392 flag1 = None
2393 flag2 = None
2393 flag2 = None
2394 if f1:
2394 if f1:
2395 content1 = getfilectx(f1, ctx1).data()
2395 content1 = getfilectx(f1, ctx1).data()
2396 if opts.git or losedatafn:
2396 if opts.git or losedatafn:
2397 flag1 = ctx1.flags(f1)
2397 flag1 = ctx1.flags(f1)
2398 if f2:
2398 if f2:
2399 content2 = getfilectx(f2, ctx2).data()
2399 content2 = getfilectx(f2, ctx2).data()
2400 if opts.git or losedatafn:
2400 if opts.git or losedatafn:
2401 flag2 = ctx2.flags(f2)
2401 flag2 = ctx2.flags(f2)
2402 binary = False
2402 binary = False
2403 if opts.git or losedatafn:
2403 if opts.git or losedatafn:
2404 binary = util.binary(content1) or util.binary(content2)
2404 binary = util.binary(content1) or util.binary(content2)
2405
2405
2406 if losedatafn and not opts.git:
2406 if losedatafn and not opts.git:
2407 if (binary or
2407 if (binary or
2408 # copy/rename
2408 # copy/rename
2409 f2 in copy or
2409 f2 in copy or
2410 # empty file creation
2410 # empty file creation
2411 (not f1 and not content2) or
2411 (not f1 and not content2) or
2412 # empty file deletion
2412 # empty file deletion
2413 (not content1 and not f2) or
2413 (not content1 and not f2) or
2414 # create with flags
2414 # create with flags
2415 (not f1 and flag2) or
2415 (not f1 and flag2) or
2416 # change flags
2416 # change flags
2417 (f1 and f2 and flag1 != flag2)):
2417 (f1 and f2 and flag1 != flag2)):
2418 losedatafn(f2 or f1)
2418 losedatafn(f2 or f1)
2419
2419
2420 path1 = f1 or f2
2420 path1 = f1 or f2
2421 path2 = f2 or f1
2421 path2 = f2 or f1
2422 path1 = posixpath.join(prefix, path1[len(relroot):])
2422 path1 = posixpath.join(prefix, path1[len(relroot):])
2423 path2 = posixpath.join(prefix, path2[len(relroot):])
2423 path2 = posixpath.join(prefix, path2[len(relroot):])
2424 header = []
2424 header = []
2425 if opts.git:
2425 if opts.git:
2426 header.append('diff --git %s%s %s%s' %
2426 header.append('diff --git %s%s %s%s' %
2427 (aprefix, path1, bprefix, path2))
2427 (aprefix, path1, bprefix, path2))
2428 if not f1: # added
2428 if not f1: # added
2429 header.append('new file mode %s' % gitmode[flag2])
2429 header.append('new file mode %s' % gitmode[flag2])
2430 elif not f2: # removed
2430 elif not f2: # removed
2431 header.append('deleted file mode %s' % gitmode[flag1])
2431 header.append('deleted file mode %s' % gitmode[flag1])
2432 else: # modified/copied/renamed
2432 else: # modified/copied/renamed
2433 mode1, mode2 = gitmode[flag1], gitmode[flag2]
2433 mode1, mode2 = gitmode[flag1], gitmode[flag2]
2434 if mode1 != mode2:
2434 if mode1 != mode2:
2435 header.append('old mode %s' % mode1)
2435 header.append('old mode %s' % mode1)
2436 header.append('new mode %s' % mode2)
2436 header.append('new mode %s' % mode2)
2437 if copyop is not None:
2437 if copyop is not None:
2438 header.append('%s from %s' % (copyop, path1))
2438 header.append('%s from %s' % (copyop, path1))
2439 header.append('%s to %s' % (copyop, path2))
2439 header.append('%s to %s' % (copyop, path2))
2440 elif revs and not repo.ui.quiet:
2440 elif revs and not repo.ui.quiet:
2441 header.append(diffline(path1, revs))
2441 header.append(diffline(path1, revs))
2442
2442
2443 if binary and opts.git and not opts.nobinary:
2443 if binary and opts.git and not opts.nobinary:
2444 text = mdiff.b85diff(content1, content2)
2444 text = mdiff.b85diff(content1, content2)
2445 if text:
2445 if text:
2446 header.append('index %s..%s' %
2446 header.append('index %s..%s' %
2447 (gitindex(content1), gitindex(content2)))
2447 (gitindex(content1), gitindex(content2)))
2448 else:
2448 else:
2449 text = mdiff.unidiff(content1, date1,
2449 text = mdiff.unidiff(content1, date1,
2450 content2, date2,
2450 content2, date2,
2451 path1, path2, opts=opts)
2451 path1, path2, opts=opts)
2452 if header and (text or len(header) > 1):
2452 if header and (text or len(header) > 1):
2453 yield '\n'.join(header) + '\n'
2453 yield '\n'.join(header) + '\n'
2454 if text:
2454 if text:
2455 yield text
2455 yield text
2456
2456
2457 def diffstatsum(stats):
2457 def diffstatsum(stats):
2458 maxfile, maxtotal, addtotal, removetotal, binary = 0, 0, 0, 0, False
2458 maxfile, maxtotal, addtotal, removetotal, binary = 0, 0, 0, 0, False
2459 for f, a, r, b in stats:
2459 for f, a, r, b in stats:
2460 maxfile = max(maxfile, encoding.colwidth(f))
2460 maxfile = max(maxfile, encoding.colwidth(f))
2461 maxtotal = max(maxtotal, a + r)
2461 maxtotal = max(maxtotal, a + r)
2462 addtotal += a
2462 addtotal += a
2463 removetotal += r
2463 removetotal += r
2464 binary = binary or b
2464 binary = binary or b
2465
2465
2466 return maxfile, maxtotal, addtotal, removetotal, binary
2466 return maxfile, maxtotal, addtotal, removetotal, binary
2467
2467
2468 def diffstatdata(lines):
2468 def diffstatdata(lines):
2469 diffre = re.compile('^diff .*-r [a-z0-9]+\s(.*)$')
2469 diffre = re.compile('^diff .*-r [a-z0-9]+\s(.*)$')
2470
2470
2471 results = []
2471 results = []
2472 filename, adds, removes, isbinary = None, 0, 0, False
2472 filename, adds, removes, isbinary = None, 0, 0, False
2473
2473
2474 def addresult():
2474 def addresult():
2475 if filename:
2475 if filename:
2476 results.append((filename, adds, removes, isbinary))
2476 results.append((filename, adds, removes, isbinary))
2477
2477
2478 for line in lines:
2478 for line in lines:
2479 if line.startswith('diff'):
2479 if line.startswith('diff'):
2480 addresult()
2480 addresult()
2481 # set numbers to 0 anyway when starting new file
2481 # set numbers to 0 anyway when starting new file
2482 adds, removes, isbinary = 0, 0, False
2482 adds, removes, isbinary = 0, 0, False
2483 if line.startswith('diff --git a/'):
2483 if line.startswith('diff --git a/'):
2484 filename = gitre.search(line).group(2)
2484 filename = gitre.search(line).group(2)
2485 elif line.startswith('diff -r'):
2485 elif line.startswith('diff -r'):
2486 # format: "diff -r ... -r ... filename"
2486 # format: "diff -r ... -r ... filename"
2487 filename = diffre.search(line).group(1)
2487 filename = diffre.search(line).group(1)
2488 elif line.startswith('+') and not line.startswith('+++ '):
2488 elif line.startswith('+') and not line.startswith('+++ '):
2489 adds += 1
2489 adds += 1
2490 elif line.startswith('-') and not line.startswith('--- '):
2490 elif line.startswith('-') and not line.startswith('--- '):
2491 removes += 1
2491 removes += 1
2492 elif (line.startswith('GIT binary patch') or
2492 elif (line.startswith('GIT binary patch') or
2493 line.startswith('Binary file')):
2493 line.startswith('Binary file')):
2494 isbinary = True
2494 isbinary = True
2495 addresult()
2495 addresult()
2496 return results
2496 return results
2497
2497
2498 def diffstat(lines, width=80, git=False):
2498 def diffstat(lines, width=80, git=False):
2499 output = []
2499 output = []
2500 stats = diffstatdata(lines)
2500 stats = diffstatdata(lines)
2501 maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
2501 maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
2502
2502
2503 countwidth = len(str(maxtotal))
2503 countwidth = len(str(maxtotal))
2504 if hasbinary and countwidth < 3:
2504 if hasbinary and countwidth < 3:
2505 countwidth = 3
2505 countwidth = 3
2506 graphwidth = width - countwidth - maxname - 6
2506 graphwidth = width - countwidth - maxname - 6
2507 if graphwidth < 10:
2507 if graphwidth < 10:
2508 graphwidth = 10
2508 graphwidth = 10
2509
2509
2510 def scale(i):
2510 def scale(i):
2511 if maxtotal <= graphwidth:
2511 if maxtotal <= graphwidth:
2512 return i
2512 return i
2513 # If diffstat runs out of room it doesn't print anything,
2513 # If diffstat runs out of room it doesn't print anything,
2514 # which isn't very useful, so always print at least one + or -
2514 # which isn't very useful, so always print at least one + or -
2515 # if there were at least some changes.
2515 # if there were at least some changes.
2516 return max(i * graphwidth // maxtotal, int(bool(i)))
2516 return max(i * graphwidth // maxtotal, int(bool(i)))
2517
2517
2518 for filename, adds, removes, isbinary in stats:
2518 for filename, adds, removes, isbinary in stats:
2519 if isbinary:
2519 if isbinary:
2520 count = 'Bin'
2520 count = 'Bin'
2521 else:
2521 else:
2522 count = adds + removes
2522 count = adds + removes
2523 pluses = '+' * scale(adds)
2523 pluses = '+' * scale(adds)
2524 minuses = '-' * scale(removes)
2524 minuses = '-' * scale(removes)
2525 output.append(' %s%s | %*s %s%s\n' %
2525 output.append(' %s%s | %*s %s%s\n' %
2526 (filename, ' ' * (maxname - encoding.colwidth(filename)),
2526 (filename, ' ' * (maxname - encoding.colwidth(filename)),
2527 countwidth, count, pluses, minuses))
2527 countwidth, count, pluses, minuses))
2528
2528
2529 if stats:
2529 if stats:
2530 output.append(_(' %d files changed, %d insertions(+), '
2530 output.append(_(' %d files changed, %d insertions(+), '
2531 '%d deletions(-)\n')
2531 '%d deletions(-)\n')
2532 % (len(stats), totaladds, totalremoves))
2532 % (len(stats), totaladds, totalremoves))
2533
2533
2534 return ''.join(output)
2534 return ''.join(output)
2535
2535
2536 def diffstatui(*args, **kw):
2536 def diffstatui(*args, **kw):
2537 '''like diffstat(), but yields 2-tuples of (output, label) for
2537 '''like diffstat(), but yields 2-tuples of (output, label) for
2538 ui.write()
2538 ui.write()
2539 '''
2539 '''
2540
2540
2541 for line in diffstat(*args, **kw).splitlines():
2541 for line in diffstat(*args, **kw).splitlines():
2542 if line and line[-1] in '+-':
2542 if line and line[-1] in '+-':
2543 name, graph = line.rsplit(' ', 1)
2543 name, graph = line.rsplit(' ', 1)
2544 yield (name + ' ', '')
2544 yield (name + ' ', '')
2545 m = re.search(r'\++', graph)
2545 m = re.search(r'\++', graph)
2546 if m:
2546 if m:
2547 yield (m.group(0), 'diffstat.inserted')
2547 yield (m.group(0), 'diffstat.inserted')
2548 m = re.search(r'-+', graph)
2548 m = re.search(r'-+', graph)
2549 if m:
2549 if m:
2550 yield (m.group(0), 'diffstat.deleted')
2550 yield (m.group(0), 'diffstat.deleted')
2551 else:
2551 else:
2552 yield (line, '')
2552 yield (line, '')
2553 yield ('\n', '')
2553 yield ('\n', '')
@@ -1,1500 +1,1507
1 $ hg init a
1 $ hg init a
2 $ mkdir a/d1
2 $ mkdir a/d1
3 $ mkdir a/d1/d2
3 $ mkdir a/d1/d2
4 $ echo line 1 > a/a
4 $ echo line 1 > a/a
5 $ echo line 1 > a/d1/d2/a
5 $ echo line 1 > a/d1/d2/a
6 $ hg --cwd a ci -Ama
6 $ hg --cwd a ci -Ama
7 adding a
7 adding a
8 adding d1/d2/a
8 adding d1/d2/a
9
9
10 $ echo line 2 >> a/a
10 $ echo line 2 >> a/a
11 $ hg --cwd a ci -u someone -d '1 0' -m'second change'
11 $ hg --cwd a ci -u someone -d '1 0' -m'second change'
12
12
13 import with no args:
13 import with no args:
14
14
15 $ hg --cwd a import
15 $ hg --cwd a import
16 abort: need at least one patch to import
16 abort: need at least one patch to import
17 [255]
17 [255]
18
18
19 generate patches for the test
19 generate patches for the test
20
20
21 $ hg --cwd a export tip > exported-tip.patch
21 $ hg --cwd a export tip > exported-tip.patch
22 $ hg --cwd a diff -r0:1 > diffed-tip.patch
22 $ hg --cwd a diff -r0:1 > diffed-tip.patch
23
23
24
24
25 import exported patch
25 import exported patch
26 (this also tests that editor is not invoked, if the patch contains the
26 (this also tests that editor is not invoked, if the patch contains the
27 commit message and '--edit' is not specified)
27 commit message and '--edit' is not specified)
28
28
29 $ hg clone -r0 a b
29 $ hg clone -r0 a b
30 adding changesets
30 adding changesets
31 adding manifests
31 adding manifests
32 adding file changes
32 adding file changes
33 added 1 changesets with 2 changes to 2 files
33 added 1 changesets with 2 changes to 2 files
34 updating to branch default
34 updating to branch default
35 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
35 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 $ HGEDITOR=cat hg --cwd b import ../exported-tip.patch
36 $ HGEDITOR=cat hg --cwd b import ../exported-tip.patch
37 applying ../exported-tip.patch
37 applying ../exported-tip.patch
38
38
39 message and committer and date should be same
39 message and committer and date should be same
40
40
41 $ hg --cwd b tip
41 $ hg --cwd b tip
42 changeset: 1:1d4bd90af0e4
42 changeset: 1:1d4bd90af0e4
43 tag: tip
43 tag: tip
44 user: someone
44 user: someone
45 date: Thu Jan 01 00:00:01 1970 +0000
45 date: Thu Jan 01 00:00:01 1970 +0000
46 summary: second change
46 summary: second change
47
47
48 $ rm -r b
48 $ rm -r b
49
49
50
50
51 import exported patch with external patcher
51 import exported patch with external patcher
52 (this also tests that editor is invoked, if the '--edit' is specified,
52 (this also tests that editor is invoked, if the '--edit' is specified,
53 regardless of the commit message in the patch)
53 regardless of the commit message in the patch)
54
54
55 $ cat > dummypatch.py <<EOF
55 $ cat > dummypatch.py <<EOF
56 > print 'patching file a'
56 > print 'patching file a'
57 > file('a', 'wb').write('line2\n')
57 > file('a', 'wb').write('line2\n')
58 > EOF
58 > EOF
59 $ hg clone -r0 a b
59 $ hg clone -r0 a b
60 adding changesets
60 adding changesets
61 adding manifests
61 adding manifests
62 adding file changes
62 adding file changes
63 added 1 changesets with 2 changes to 2 files
63 added 1 changesets with 2 changes to 2 files
64 updating to branch default
64 updating to branch default
65 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 $ HGEDITOR=cat hg --config ui.patch='python ../dummypatch.py' --cwd b import --edit ../exported-tip.patch
66 $ HGEDITOR=cat hg --config ui.patch='python ../dummypatch.py' --cwd b import --edit ../exported-tip.patch
67 applying ../exported-tip.patch
67 applying ../exported-tip.patch
68 second change
68 second change
69
69
70
70
71 HG: Enter commit message. Lines beginning with 'HG:' are removed.
71 HG: Enter commit message. Lines beginning with 'HG:' are removed.
72 HG: Leave message empty to abort commit.
72 HG: Leave message empty to abort commit.
73 HG: --
73 HG: --
74 HG: user: someone
74 HG: user: someone
75 HG: branch 'default'
75 HG: branch 'default'
76 HG: changed a
76 HG: changed a
77 $ cat b/a
77 $ cat b/a
78 line2
78 line2
79 $ rm -r b
79 $ rm -r b
80
80
81
81
82 import of plain diff should fail without message
82 import of plain diff should fail without message
83 (this also tests that editor is invoked, if the patch doesn't contain
83 (this also tests that editor is invoked, if the patch doesn't contain
84 the commit message, regardless of '--edit')
84 the commit message, regardless of '--edit')
85
85
86 $ hg clone -r0 a b
86 $ hg clone -r0 a b
87 adding changesets
87 adding changesets
88 adding manifests
88 adding manifests
89 adding file changes
89 adding file changes
90 added 1 changesets with 2 changes to 2 files
90 added 1 changesets with 2 changes to 2 files
91 updating to branch default
91 updating to branch default
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 $ cat > $TESTTMP/editor.sh <<EOF
93 $ cat > $TESTTMP/editor.sh <<EOF
94 > env | grep HGEDITFORM
94 > env | grep HGEDITFORM
95 > cat \$1
95 > cat \$1
96 > EOF
96 > EOF
97 $ HGEDITOR="sh $TESTTMP/editor.sh" hg --cwd b import ../diffed-tip.patch
97 $ HGEDITOR="sh $TESTTMP/editor.sh" hg --cwd b import ../diffed-tip.patch
98 applying ../diffed-tip.patch
98 applying ../diffed-tip.patch
99 HGEDITFORM=import.normal.normal
99 HGEDITFORM=import.normal.normal
100
100
101
101
102 HG: Enter commit message. Lines beginning with 'HG:' are removed.
102 HG: Enter commit message. Lines beginning with 'HG:' are removed.
103 HG: Leave message empty to abort commit.
103 HG: Leave message empty to abort commit.
104 HG: --
104 HG: --
105 HG: user: test
105 HG: user: test
106 HG: branch 'default'
106 HG: branch 'default'
107 HG: changed a
107 HG: changed a
108 abort: empty commit message
108 abort: empty commit message
109 [255]
109 [255]
110
110
111 Test avoiding editor invocation at applying the patch with --exact,
111 Test avoiding editor invocation at applying the patch with --exact,
112 even if commit message is empty
112 even if commit message is empty
113
113
114 $ echo a >> b/a
114 $ echo a >> b/a
115 $ hg --cwd b commit -m ' '
115 $ hg --cwd b commit -m ' '
116 $ hg --cwd b tip -T "{node}\n"
116 $ hg --cwd b tip -T "{node}\n"
117 d8804f3f5396d800812f579c8452796a5993bdb2
117 d8804f3f5396d800812f579c8452796a5993bdb2
118 $ hg --cwd b export -o ../empty-log.diff .
118 $ hg --cwd b export -o ../empty-log.diff .
119 $ hg --cwd b update -q -C ".^1"
119 $ hg --cwd b update -q -C ".^1"
120 $ hg --cwd b --config extensions.strip= strip -q tip
120 $ hg --cwd b --config extensions.strip= strip -q tip
121 $ HGEDITOR=cat hg --cwd b import --exact ../empty-log.diff
121 $ HGEDITOR=cat hg --cwd b import --exact ../empty-log.diff
122 applying ../empty-log.diff
122 applying ../empty-log.diff
123 $ hg --cwd b tip -T "{node}\n"
123 $ hg --cwd b tip -T "{node}\n"
124 d8804f3f5396d800812f579c8452796a5993bdb2
124 d8804f3f5396d800812f579c8452796a5993bdb2
125
125
126 $ rm -r b
126 $ rm -r b
127
127
128
128
129 import of plain diff should be ok with message
129 import of plain diff should be ok with message
130
130
131 $ hg clone -r0 a b
131 $ hg clone -r0 a b
132 adding changesets
132 adding changesets
133 adding manifests
133 adding manifests
134 adding file changes
134 adding file changes
135 added 1 changesets with 2 changes to 2 files
135 added 1 changesets with 2 changes to 2 files
136 updating to branch default
136 updating to branch default
137 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
138 $ hg --cwd b import -mpatch ../diffed-tip.patch
138 $ hg --cwd b import -mpatch ../diffed-tip.patch
139 applying ../diffed-tip.patch
139 applying ../diffed-tip.patch
140 $ rm -r b
140 $ rm -r b
141
141
142
142
143 import of plain diff with specific date and user
143 import of plain diff with specific date and user
144 (this also tests that editor is not invoked, if
144 (this also tests that editor is not invoked, if
145 '--message'/'--logfile' is specified and '--edit' is not)
145 '--message'/'--logfile' is specified and '--edit' is not)
146
146
147 $ hg clone -r0 a b
147 $ hg clone -r0 a b
148 adding changesets
148 adding changesets
149 adding manifests
149 adding manifests
150 adding file changes
150 adding file changes
151 added 1 changesets with 2 changes to 2 files
151 added 1 changesets with 2 changes to 2 files
152 updating to branch default
152 updating to branch default
153 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
154 $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
155 applying ../diffed-tip.patch
155 applying ../diffed-tip.patch
156 $ hg -R b tip -pv
156 $ hg -R b tip -pv
157 changeset: 1:ca68f19f3a40
157 changeset: 1:ca68f19f3a40
158 tag: tip
158 tag: tip
159 user: user@nowhere.net
159 user: user@nowhere.net
160 date: Thu Jan 01 00:00:01 1970 +0000
160 date: Thu Jan 01 00:00:01 1970 +0000
161 files: a
161 files: a
162 description:
162 description:
163 patch
163 patch
164
164
165
165
166 diff -r 80971e65b431 -r ca68f19f3a40 a
166 diff -r 80971e65b431 -r ca68f19f3a40 a
167 --- a/a Thu Jan 01 00:00:00 1970 +0000
167 --- a/a Thu Jan 01 00:00:00 1970 +0000
168 +++ b/a Thu Jan 01 00:00:01 1970 +0000
168 +++ b/a Thu Jan 01 00:00:01 1970 +0000
169 @@ -1,1 +1,2 @@
169 @@ -1,1 +1,2 @@
170 line 1
170 line 1
171 +line 2
171 +line 2
172
172
173 $ rm -r b
173 $ rm -r b
174
174
175
175
176 import of plain diff should be ok with --no-commit
176 import of plain diff should be ok with --no-commit
177 (this also tests that editor is not invoked, if '--no-commit' is
177 (this also tests that editor is not invoked, if '--no-commit' is
178 specified, regardless of '--edit')
178 specified, regardless of '--edit')
179
179
180 $ hg clone -r0 a b
180 $ hg clone -r0 a b
181 adding changesets
181 adding changesets
182 adding manifests
182 adding manifests
183 adding file changes
183 adding file changes
184 added 1 changesets with 2 changes to 2 files
184 added 1 changesets with 2 changes to 2 files
185 updating to branch default
185 updating to branch default
186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ HGEDITOR=cat hg --cwd b import --no-commit --edit ../diffed-tip.patch
187 $ HGEDITOR=cat hg --cwd b import --no-commit --edit ../diffed-tip.patch
188 applying ../diffed-tip.patch
188 applying ../diffed-tip.patch
189 $ hg --cwd b diff --nodates
189 $ hg --cwd b diff --nodates
190 diff -r 80971e65b431 a
190 diff -r 80971e65b431 a
191 --- a/a
191 --- a/a
192 +++ b/a
192 +++ b/a
193 @@ -1,1 +1,2 @@
193 @@ -1,1 +1,2 @@
194 line 1
194 line 1
195 +line 2
195 +line 2
196 $ rm -r b
196 $ rm -r b
197
197
198
198
199 import of malformed plain diff should fail
199 import of malformed plain diff should fail
200
200
201 $ hg clone -r0 a b
201 $ hg clone -r0 a b
202 adding changesets
202 adding changesets
203 adding manifests
203 adding manifests
204 adding file changes
204 adding file changes
205 added 1 changesets with 2 changes to 2 files
205 added 1 changesets with 2 changes to 2 files
206 updating to branch default
206 updating to branch default
207 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
208 $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
209 $ hg --cwd b import -mpatch ../broken.patch
209 $ hg --cwd b import -mpatch ../broken.patch
210 applying ../broken.patch
210 applying ../broken.patch
211 abort: bad hunk #1
211 abort: bad hunk #1
212 [255]
212 [255]
213 $ rm -r b
213 $ rm -r b
214
214
215
215
216 hg -R repo import
216 hg -R repo import
217 put the clone in a subdir - having a directory named "a"
217 put the clone in a subdir - having a directory named "a"
218 used to hide a bug.
218 used to hide a bug.
219
219
220 $ mkdir dir
220 $ mkdir dir
221 $ hg clone -r0 a dir/b
221 $ hg clone -r0 a dir/b
222 adding changesets
222 adding changesets
223 adding manifests
223 adding manifests
224 adding file changes
224 adding file changes
225 added 1 changesets with 2 changes to 2 files
225 added 1 changesets with 2 changes to 2 files
226 updating to branch default
226 updating to branch default
227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
228 $ cd dir
228 $ cd dir
229 $ hg -R b import ../exported-tip.patch
229 $ hg -R b import ../exported-tip.patch
230 applying ../exported-tip.patch
230 applying ../exported-tip.patch
231 $ cd ..
231 $ cd ..
232 $ rm -r dir
232 $ rm -r dir
233
233
234
234
235 import from stdin
235 import from stdin
236
236
237 $ hg clone -r0 a b
237 $ hg clone -r0 a b
238 adding changesets
238 adding changesets
239 adding manifests
239 adding manifests
240 adding file changes
240 adding file changes
241 added 1 changesets with 2 changes to 2 files
241 added 1 changesets with 2 changes to 2 files
242 updating to branch default
242 updating to branch default
243 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 $ hg --cwd b import - < exported-tip.patch
244 $ hg --cwd b import - < exported-tip.patch
245 applying patch from stdin
245 applying patch from stdin
246 $ rm -r b
246 $ rm -r b
247
247
248
248
249 import two patches in one stream
249 import two patches in one stream
250
250
251 $ hg init b
251 $ hg init b
252 $ hg --cwd a export 0:tip | hg --cwd b import -
252 $ hg --cwd a export 0:tip | hg --cwd b import -
253 applying patch from stdin
253 applying patch from stdin
254 $ hg --cwd a id
254 $ hg --cwd a id
255 1d4bd90af0e4 tip
255 1d4bd90af0e4 tip
256 $ hg --cwd b id
256 $ hg --cwd b id
257 1d4bd90af0e4 tip
257 1d4bd90af0e4 tip
258 $ rm -r b
258 $ rm -r b
259
259
260
260
261 override commit message
261 override commit message
262
262
263 $ hg clone -r0 a b
263 $ hg clone -r0 a b
264 adding changesets
264 adding changesets
265 adding manifests
265 adding manifests
266 adding file changes
266 adding file changes
267 added 1 changesets with 2 changes to 2 files
267 added 1 changesets with 2 changes to 2 files
268 updating to branch default
268 updating to branch default
269 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
270 $ hg --cwd b import -m 'override' - < exported-tip.patch
270 $ hg --cwd b import -m 'override' - < exported-tip.patch
271 applying patch from stdin
271 applying patch from stdin
272 $ hg --cwd b tip | grep override
272 $ hg --cwd b tip | grep override
273 summary: override
273 summary: override
274 $ rm -r b
274 $ rm -r b
275
275
276 $ cat > mkmsg.py <<EOF
276 $ cat > mkmsg.py <<EOF
277 > import email.Message, sys
277 > import email.Message, sys
278 > msg = email.Message.Message()
278 > msg = email.Message.Message()
279 > patch = open(sys.argv[1], 'rb').read()
279 > patch = open(sys.argv[1], 'rb').read()
280 > msg.set_payload('email commit message\n' + patch)
280 > msg.set_payload('email commit message\n' + patch)
281 > msg['Subject'] = 'email patch'
281 > msg['Subject'] = 'email patch'
282 > msg['From'] = 'email patcher'
282 > msg['From'] = 'email patcher'
283 > file(sys.argv[2], 'wb').write(msg.as_string())
283 > file(sys.argv[2], 'wb').write(msg.as_string())
284 > EOF
284 > EOF
285
285
286
286
287 plain diff in email, subject, message body
287 plain diff in email, subject, message body
288
288
289 $ hg clone -r0 a b
289 $ hg clone -r0 a b
290 adding changesets
290 adding changesets
291 adding manifests
291 adding manifests
292 adding file changes
292 adding file changes
293 added 1 changesets with 2 changes to 2 files
293 added 1 changesets with 2 changes to 2 files
294 updating to branch default
294 updating to branch default
295 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 $ python mkmsg.py diffed-tip.patch msg.patch
296 $ python mkmsg.py diffed-tip.patch msg.patch
297 $ hg --cwd b import ../msg.patch
297 $ hg --cwd b import ../msg.patch
298 applying ../msg.patch
298 applying ../msg.patch
299 $ hg --cwd b tip | grep email
299 $ hg --cwd b tip | grep email
300 user: email patcher
300 user: email patcher
301 summary: email patch
301 summary: email patch
302 $ rm -r b
302 $ rm -r b
303
303
304
304
305 plain diff in email, no subject, message body
305 plain diff in email, no subject, message body
306
306
307 $ hg clone -r0 a b
307 $ hg clone -r0 a b
308 adding changesets
308 adding changesets
309 adding manifests
309 adding manifests
310 adding file changes
310 adding file changes
311 added 1 changesets with 2 changes to 2 files
311 added 1 changesets with 2 changes to 2 files
312 updating to branch default
312 updating to branch default
313 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 $ grep -v '^Subject:' msg.patch | hg --cwd b import -
314 $ grep -v '^Subject:' msg.patch | hg --cwd b import -
315 applying patch from stdin
315 applying patch from stdin
316 $ rm -r b
316 $ rm -r b
317
317
318
318
319 plain diff in email, subject, no message body
319 plain diff in email, subject, no message body
320
320
321 $ hg clone -r0 a b
321 $ hg clone -r0 a b
322 adding changesets
322 adding changesets
323 adding manifests
323 adding manifests
324 adding file changes
324 adding file changes
325 added 1 changesets with 2 changes to 2 files
325 added 1 changesets with 2 changes to 2 files
326 updating to branch default
326 updating to branch default
327 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
327 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
328 $ grep -v '^email ' msg.patch | hg --cwd b import -
328 $ grep -v '^email ' msg.patch | hg --cwd b import -
329 applying patch from stdin
329 applying patch from stdin
330 $ rm -r b
330 $ rm -r b
331
331
332
332
333 plain diff in email, no subject, no message body, should fail
333 plain diff in email, no subject, no message body, should fail
334
334
335 $ hg clone -r0 a b
335 $ hg clone -r0 a b
336 adding changesets
336 adding changesets
337 adding manifests
337 adding manifests
338 adding file changes
338 adding file changes
339 added 1 changesets with 2 changes to 2 files
339 added 1 changesets with 2 changes to 2 files
340 updating to branch default
340 updating to branch default
341 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
342 $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
343 applying patch from stdin
343 applying patch from stdin
344 abort: empty commit message
344 abort: empty commit message
345 [255]
345 [255]
346 $ rm -r b
346 $ rm -r b
347
347
348
348
349 hg export in email, should use patch header
349 hg export in email, should use patch header
350
350
351 $ hg clone -r0 a b
351 $ hg clone -r0 a b
352 adding changesets
352 adding changesets
353 adding manifests
353 adding manifests
354 adding file changes
354 adding file changes
355 added 1 changesets with 2 changes to 2 files
355 added 1 changesets with 2 changes to 2 files
356 updating to branch default
356 updating to branch default
357 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 $ python mkmsg.py exported-tip.patch msg.patch
358 $ python mkmsg.py exported-tip.patch msg.patch
359 $ cat msg.patch | hg --cwd b import -
359 $ cat msg.patch | hg --cwd b import -
360 applying patch from stdin
360 applying patch from stdin
361 $ hg --cwd b tip | grep second
361 $ hg --cwd b tip | grep second
362 summary: second change
362 summary: second change
363 $ rm -r b
363 $ rm -r b
364
364
365
365
366 subject: duplicate detection, removal of [PATCH]
366 subject: duplicate detection, removal of [PATCH]
367 The '---' tests the gitsendmail handling without proper mail headers
367 The '---' tests the gitsendmail handling without proper mail headers
368
368
369 $ cat > mkmsg2.py <<EOF
369 $ cat > mkmsg2.py <<EOF
370 > import email.Message, sys
370 > import email.Message, sys
371 > msg = email.Message.Message()
371 > msg = email.Message.Message()
372 > patch = open(sys.argv[1], 'rb').read()
372 > patch = open(sys.argv[1], 'rb').read()
373 > msg.set_payload('email patch\n\nnext line\n---\n' + patch)
373 > msg.set_payload('email patch\n\nnext line\n---\n' + patch)
374 > msg['Subject'] = '[PATCH] email patch'
374 > msg['Subject'] = '[PATCH] email patch'
375 > msg['From'] = 'email patcher'
375 > msg['From'] = 'email patcher'
376 > file(sys.argv[2], 'wb').write(msg.as_string())
376 > file(sys.argv[2], 'wb').write(msg.as_string())
377 > EOF
377 > EOF
378
378
379
379
380 plain diff in email, [PATCH] subject, message body with subject
380 plain diff in email, [PATCH] subject, message body with subject
381
381
382 $ hg clone -r0 a b
382 $ hg clone -r0 a b
383 adding changesets
383 adding changesets
384 adding manifests
384 adding manifests
385 adding file changes
385 adding file changes
386 added 1 changesets with 2 changes to 2 files
386 added 1 changesets with 2 changes to 2 files
387 updating to branch default
387 updating to branch default
388 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 $ python mkmsg2.py diffed-tip.patch msg.patch
389 $ python mkmsg2.py diffed-tip.patch msg.patch
390 $ cat msg.patch | hg --cwd b import -
390 $ cat msg.patch | hg --cwd b import -
391 applying patch from stdin
391 applying patch from stdin
392 $ hg --cwd b tip --template '{desc}\n'
392 $ hg --cwd b tip --template '{desc}\n'
393 email patch
393 email patch
394
394
395 next line
395 next line
396 $ rm -r b
396 $ rm -r b
397
397
398
398
399 Issue963: Parent of working dir incorrect after import of multiple
399 Issue963: Parent of working dir incorrect after import of multiple
400 patches and rollback
400 patches and rollback
401
401
402 We weren't backing up the correct dirstate file when importing many
402 We weren't backing up the correct dirstate file when importing many
403 patches: import patch1 patch2; rollback
403 patches: import patch1 patch2; rollback
404
404
405 $ echo line 3 >> a/a
405 $ echo line 3 >> a/a
406 $ hg --cwd a ci -m'third change'
406 $ hg --cwd a ci -m'third change'
407 $ hg --cwd a export -o '../patch%R' 1 2
407 $ hg --cwd a export -o '../patch%R' 1 2
408 $ hg clone -qr0 a b
408 $ hg clone -qr0 a b
409 $ hg --cwd b parents --template 'parent: {rev}\n'
409 $ hg --cwd b parents --template 'parent: {rev}\n'
410 parent: 0
410 parent: 0
411 $ hg --cwd b import -v ../patch1 ../patch2
411 $ hg --cwd b import -v ../patch1 ../patch2
412 applying ../patch1
412 applying ../patch1
413 patching file a
413 patching file a
414 committing files:
414 committing files:
415 a
415 a
416 committing manifest
416 committing manifest
417 committing changelog
417 committing changelog
418 created 1d4bd90af0e4
418 created 1d4bd90af0e4
419 applying ../patch2
419 applying ../patch2
420 patching file a
420 patching file a
421 committing files:
421 committing files:
422 a
422 a
423 committing manifest
423 committing manifest
424 committing changelog
424 committing changelog
425 created 6d019af21222
425 created 6d019af21222
426 $ hg --cwd b rollback
426 $ hg --cwd b rollback
427 repository tip rolled back to revision 0 (undo import)
427 repository tip rolled back to revision 0 (undo import)
428 working directory now based on revision 0
428 working directory now based on revision 0
429 $ hg --cwd b parents --template 'parent: {rev}\n'
429 $ hg --cwd b parents --template 'parent: {rev}\n'
430 parent: 0
430 parent: 0
431 $ rm -r b
431 $ rm -r b
432
432
433
433
434 importing a patch in a subdirectory failed at the commit stage
434 importing a patch in a subdirectory failed at the commit stage
435
435
436 $ echo line 2 >> a/d1/d2/a
436 $ echo line 2 >> a/d1/d2/a
437 $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
437 $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
438
438
439 hg import in a subdirectory
439 hg import in a subdirectory
440
440
441 $ hg clone -r0 a b
441 $ hg clone -r0 a b
442 adding changesets
442 adding changesets
443 adding manifests
443 adding manifests
444 adding file changes
444 adding file changes
445 added 1 changesets with 2 changes to 2 files
445 added 1 changesets with 2 changes to 2 files
446 updating to branch default
446 updating to branch default
447 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
447 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
448 $ hg --cwd a export tip > tmp
448 $ hg --cwd a export tip > tmp
449 $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
449 $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
450 $ dir=`pwd`
450 $ dir=`pwd`
451 $ cd b/d1/d2 2>&1 > /dev/null
451 $ cd b/d1/d2 2>&1 > /dev/null
452 $ hg import ../../../subdir-tip.patch
452 $ hg import ../../../subdir-tip.patch
453 applying ../../../subdir-tip.patch
453 applying ../../../subdir-tip.patch
454 $ cd "$dir"
454 $ cd "$dir"
455
455
456 message should be 'subdir change'
456 message should be 'subdir change'
457 committer should be 'someoneelse'
457 committer should be 'someoneelse'
458
458
459 $ hg --cwd b tip
459 $ hg --cwd b tip
460 changeset: 1:3577f5aea227
460 changeset: 1:3577f5aea227
461 tag: tip
461 tag: tip
462 user: someoneelse
462 user: someoneelse
463 date: Thu Jan 01 00:00:01 1970 +0000
463 date: Thu Jan 01 00:00:01 1970 +0000
464 summary: subdir change
464 summary: subdir change
465
465
466
466
467 should be empty
467 should be empty
468
468
469 $ hg --cwd b status
469 $ hg --cwd b status
470
470
471
471
472 Test fuzziness (ambiguous patch location, fuzz=2)
472 Test fuzziness (ambiguous patch location, fuzz=2)
473
473
474 $ hg init fuzzy
474 $ hg init fuzzy
475 $ cd fuzzy
475 $ cd fuzzy
476 $ echo line1 > a
476 $ echo line1 > a
477 $ echo line0 >> a
477 $ echo line0 >> a
478 $ echo line3 >> a
478 $ echo line3 >> a
479 $ hg ci -Am adda
479 $ hg ci -Am adda
480 adding a
480 adding a
481 $ echo line1 > a
481 $ echo line1 > a
482 $ echo line2 >> a
482 $ echo line2 >> a
483 $ echo line0 >> a
483 $ echo line0 >> a
484 $ echo line3 >> a
484 $ echo line3 >> a
485 $ hg ci -m change a
485 $ hg ci -m change a
486 $ hg export tip > fuzzy-tip.patch
486 $ hg export tip > fuzzy-tip.patch
487 $ hg up -C 0
487 $ hg up -C 0
488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 $ echo line1 > a
489 $ echo line1 > a
490 $ echo line0 >> a
490 $ echo line0 >> a
491 $ echo line1 >> a
491 $ echo line1 >> a
492 $ echo line0 >> a
492 $ echo line0 >> a
493 $ hg ci -m brancha
493 $ hg ci -m brancha
494 created new head
494 created new head
495 $ hg import --config patch.fuzz=0 -v fuzzy-tip.patch
496 applying fuzzy-tip.patch
497 patching file a
498 Hunk #1 FAILED at 0
499 1 out of 1 hunks FAILED -- saving rejects to file a.rej
500 abort: patch failed to apply
501 [255]
495 $ hg import --no-commit -v fuzzy-tip.patch
502 $ hg import --no-commit -v fuzzy-tip.patch
496 applying fuzzy-tip.patch
503 applying fuzzy-tip.patch
497 patching file a
504 patching file a
498 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
505 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
499 applied to working directory
506 applied to working directory
500 $ hg revert -a
507 $ hg revert -a
501 reverting a
508 reverting a
502
509
503
510
504 import with --no-commit should have written .hg/last-message.txt
511 import with --no-commit should have written .hg/last-message.txt
505
512
506 $ cat .hg/last-message.txt
513 $ cat .hg/last-message.txt
507 change (no-eol)
514 change (no-eol)
508
515
509
516
510 test fuzziness with eol=auto
517 test fuzziness with eol=auto
511
518
512 $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
519 $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
513 applying fuzzy-tip.patch
520 applying fuzzy-tip.patch
514 patching file a
521 patching file a
515 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
522 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
516 applied to working directory
523 applied to working directory
517 $ cd ..
524 $ cd ..
518
525
519
526
520 Test hunk touching empty files (issue906)
527 Test hunk touching empty files (issue906)
521
528
522 $ hg init empty
529 $ hg init empty
523 $ cd empty
530 $ cd empty
524 $ touch a
531 $ touch a
525 $ touch b1
532 $ touch b1
526 $ touch c1
533 $ touch c1
527 $ echo d > d
534 $ echo d > d
528 $ hg ci -Am init
535 $ hg ci -Am init
529 adding a
536 adding a
530 adding b1
537 adding b1
531 adding c1
538 adding c1
532 adding d
539 adding d
533 $ echo a > a
540 $ echo a > a
534 $ echo b > b1
541 $ echo b > b1
535 $ hg mv b1 b2
542 $ hg mv b1 b2
536 $ echo c > c1
543 $ echo c > c1
537 $ hg copy c1 c2
544 $ hg copy c1 c2
538 $ rm d
545 $ rm d
539 $ touch d
546 $ touch d
540 $ hg diff --git
547 $ hg diff --git
541 diff --git a/a b/a
548 diff --git a/a b/a
542 --- a/a
549 --- a/a
543 +++ b/a
550 +++ b/a
544 @@ -0,0 +1,1 @@
551 @@ -0,0 +1,1 @@
545 +a
552 +a
546 diff --git a/b1 b/b2
553 diff --git a/b1 b/b2
547 rename from b1
554 rename from b1
548 rename to b2
555 rename to b2
549 --- a/b1
556 --- a/b1
550 +++ b/b2
557 +++ b/b2
551 @@ -0,0 +1,1 @@
558 @@ -0,0 +1,1 @@
552 +b
559 +b
553 diff --git a/c1 b/c1
560 diff --git a/c1 b/c1
554 --- a/c1
561 --- a/c1
555 +++ b/c1
562 +++ b/c1
556 @@ -0,0 +1,1 @@
563 @@ -0,0 +1,1 @@
557 +c
564 +c
558 diff --git a/c1 b/c2
565 diff --git a/c1 b/c2
559 copy from c1
566 copy from c1
560 copy to c2
567 copy to c2
561 --- a/c1
568 --- a/c1
562 +++ b/c2
569 +++ b/c2
563 @@ -0,0 +1,1 @@
570 @@ -0,0 +1,1 @@
564 +c
571 +c
565 diff --git a/d b/d
572 diff --git a/d b/d
566 --- a/d
573 --- a/d
567 +++ b/d
574 +++ b/d
568 @@ -1,1 +0,0 @@
575 @@ -1,1 +0,0 @@
569 -d
576 -d
570 $ hg ci -m empty
577 $ hg ci -m empty
571 $ hg export --git tip > empty.diff
578 $ hg export --git tip > empty.diff
572 $ hg up -C 0
579 $ hg up -C 0
573 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
580 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
574 $ hg import empty.diff
581 $ hg import empty.diff
575 applying empty.diff
582 applying empty.diff
576 $ for name in a b1 b2 c1 c2 d; do
583 $ for name in a b1 b2 c1 c2 d; do
577 > echo % $name file
584 > echo % $name file
578 > test -f $name && cat $name
585 > test -f $name && cat $name
579 > done
586 > done
580 % a file
587 % a file
581 a
588 a
582 % b1 file
589 % b1 file
583 % b2 file
590 % b2 file
584 b
591 b
585 % c1 file
592 % c1 file
586 c
593 c
587 % c2 file
594 % c2 file
588 c
595 c
589 % d file
596 % d file
590 $ cd ..
597 $ cd ..
591
598
592
599
593 Test importing a patch ending with a binary file removal
600 Test importing a patch ending with a binary file removal
594
601
595 $ hg init binaryremoval
602 $ hg init binaryremoval
596 $ cd binaryremoval
603 $ cd binaryremoval
597 $ echo a > a
604 $ echo a > a
598 $ $PYTHON -c "file('b', 'wb').write('a\x00b')"
605 $ $PYTHON -c "file('b', 'wb').write('a\x00b')"
599 $ hg ci -Am addall
606 $ hg ci -Am addall
600 adding a
607 adding a
601 adding b
608 adding b
602 $ hg rm a
609 $ hg rm a
603 $ hg rm b
610 $ hg rm b
604 $ hg st
611 $ hg st
605 R a
612 R a
606 R b
613 R b
607 $ hg ci -m remove
614 $ hg ci -m remove
608 $ hg export --git . > remove.diff
615 $ hg export --git . > remove.diff
609 $ cat remove.diff | grep git
616 $ cat remove.diff | grep git
610 diff --git a/a b/a
617 diff --git a/a b/a
611 diff --git a/b b/b
618 diff --git a/b b/b
612 $ hg up -C 0
619 $ hg up -C 0
613 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
620 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
614 $ hg import remove.diff
621 $ hg import remove.diff
615 applying remove.diff
622 applying remove.diff
616 $ hg manifest
623 $ hg manifest
617 $ cd ..
624 $ cd ..
618
625
619
626
620 Issue927: test update+rename with common name
627 Issue927: test update+rename with common name
621
628
622 $ hg init t
629 $ hg init t
623 $ cd t
630 $ cd t
624 $ touch a
631 $ touch a
625 $ hg ci -Am t
632 $ hg ci -Am t
626 adding a
633 adding a
627 $ echo a > a
634 $ echo a > a
628
635
629 Here, bfile.startswith(afile)
636 Here, bfile.startswith(afile)
630
637
631 $ hg copy a a2
638 $ hg copy a a2
632 $ hg ci -m copya
639 $ hg ci -m copya
633 $ hg export --git tip > copy.diff
640 $ hg export --git tip > copy.diff
634 $ hg up -C 0
641 $ hg up -C 0
635 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
642 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
636 $ hg import copy.diff
643 $ hg import copy.diff
637 applying copy.diff
644 applying copy.diff
638
645
639 a should contain an 'a'
646 a should contain an 'a'
640
647
641 $ cat a
648 $ cat a
642 a
649 a
643
650
644 and a2 should have duplicated it
651 and a2 should have duplicated it
645
652
646 $ cat a2
653 $ cat a2
647 a
654 a
648 $ cd ..
655 $ cd ..
649
656
650
657
651 test -p0
658 test -p0
652
659
653 $ hg init p0
660 $ hg init p0
654 $ cd p0
661 $ cd p0
655 $ echo a > a
662 $ echo a > a
656 $ hg ci -Am t
663 $ hg ci -Am t
657 adding a
664 adding a
658 $ hg import -p foo
665 $ hg import -p foo
659 abort: invalid value 'foo' for option -p, expected int
666 abort: invalid value 'foo' for option -p, expected int
660 [255]
667 [255]
661 $ hg import -p0 - << EOF
668 $ hg import -p0 - << EOF
662 > foobar
669 > foobar
663 > --- a Sat Apr 12 22:43:58 2008 -0400
670 > --- a Sat Apr 12 22:43:58 2008 -0400
664 > +++ a Sat Apr 12 22:44:05 2008 -0400
671 > +++ a Sat Apr 12 22:44:05 2008 -0400
665 > @@ -1,1 +1,1 @@
672 > @@ -1,1 +1,1 @@
666 > -a
673 > -a
667 > +bb
674 > +bb
668 > EOF
675 > EOF
669 applying patch from stdin
676 applying patch from stdin
670 $ hg status
677 $ hg status
671 $ cat a
678 $ cat a
672 bb
679 bb
673
680
674 test --prefix
681 test --prefix
675
682
676 $ mkdir -p dir/dir2
683 $ mkdir -p dir/dir2
677 $ echo b > dir/dir2/b
684 $ echo b > dir/dir2/b
678 $ hg ci -Am b
685 $ hg ci -Am b
679 adding dir/dir2/b
686 adding dir/dir2/b
680 $ hg import -p2 --prefix dir - << EOF
687 $ hg import -p2 --prefix dir - << EOF
681 > foobar
688 > foobar
682 > --- drop1/drop2/dir2/b
689 > --- drop1/drop2/dir2/b
683 > +++ drop1/drop2/dir2/b
690 > +++ drop1/drop2/dir2/b
684 > @@ -1,1 +1,1 @@
691 > @@ -1,1 +1,1 @@
685 > -b
692 > -b
686 > +cc
693 > +cc
687 > EOF
694 > EOF
688 applying patch from stdin
695 applying patch from stdin
689 $ hg status
696 $ hg status
690 $ cat dir/dir2/b
697 $ cat dir/dir2/b
691 cc
698 cc
692 $ cd ..
699 $ cd ..
693
700
694
701
695 test paths outside repo root
702 test paths outside repo root
696
703
697 $ mkdir outside
704 $ mkdir outside
698 $ touch outside/foo
705 $ touch outside/foo
699 $ hg init inside
706 $ hg init inside
700 $ cd inside
707 $ cd inside
701 $ hg import - <<EOF
708 $ hg import - <<EOF
702 > diff --git a/a b/b
709 > diff --git a/a b/b
703 > rename from ../outside/foo
710 > rename from ../outside/foo
704 > rename to bar
711 > rename to bar
705 > EOF
712 > EOF
706 applying patch from stdin
713 applying patch from stdin
707 abort: path contains illegal component: ../outside/foo (glob)
714 abort: path contains illegal component: ../outside/foo (glob)
708 [255]
715 [255]
709 $ cd ..
716 $ cd ..
710
717
711
718
712 test import with similarity and git and strip (issue295 et al.)
719 test import with similarity and git and strip (issue295 et al.)
713
720
714 $ hg init sim
721 $ hg init sim
715 $ cd sim
722 $ cd sim
716 $ echo 'this is a test' > a
723 $ echo 'this is a test' > a
717 $ hg ci -Ama
724 $ hg ci -Ama
718 adding a
725 adding a
719 $ cat > ../rename.diff <<EOF
726 $ cat > ../rename.diff <<EOF
720 > diff --git a/foo/a b/foo/a
727 > diff --git a/foo/a b/foo/a
721 > deleted file mode 100644
728 > deleted file mode 100644
722 > --- a/foo/a
729 > --- a/foo/a
723 > +++ /dev/null
730 > +++ /dev/null
724 > @@ -1,1 +0,0 @@
731 > @@ -1,1 +0,0 @@
725 > -this is a test
732 > -this is a test
726 > diff --git a/foo/b b/foo/b
733 > diff --git a/foo/b b/foo/b
727 > new file mode 100644
734 > new file mode 100644
728 > --- /dev/null
735 > --- /dev/null
729 > +++ b/foo/b
736 > +++ b/foo/b
730 > @@ -0,0 +1,2 @@
737 > @@ -0,0 +1,2 @@
731 > +this is a test
738 > +this is a test
732 > +foo
739 > +foo
733 > EOF
740 > EOF
734 $ hg import --no-commit -v -s 1 ../rename.diff -p2
741 $ hg import --no-commit -v -s 1 ../rename.diff -p2
735 applying ../rename.diff
742 applying ../rename.diff
736 patching file a
743 patching file a
737 patching file b
744 patching file b
738 adding b
745 adding b
739 recording removal of a as rename to b (88% similar)
746 recording removal of a as rename to b (88% similar)
740 applied to working directory
747 applied to working directory
741 $ hg st -C
748 $ hg st -C
742 A b
749 A b
743 a
750 a
744 R a
751 R a
745 $ hg revert -a
752 $ hg revert -a
746 undeleting a
753 undeleting a
747 forgetting b
754 forgetting b
748 $ rm b
755 $ rm b
749 $ hg import --no-commit -v -s 100 ../rename.diff -p2
756 $ hg import --no-commit -v -s 100 ../rename.diff -p2
750 applying ../rename.diff
757 applying ../rename.diff
751 patching file a
758 patching file a
752 patching file b
759 patching file b
753 adding b
760 adding b
754 applied to working directory
761 applied to working directory
755 $ hg st -C
762 $ hg st -C
756 A b
763 A b
757 R a
764 R a
758 $ cd ..
765 $ cd ..
759
766
760
767
761 Issue1495: add empty file from the end of patch
768 Issue1495: add empty file from the end of patch
762
769
763 $ hg init addemptyend
770 $ hg init addemptyend
764 $ cd addemptyend
771 $ cd addemptyend
765 $ touch a
772 $ touch a
766 $ hg addremove
773 $ hg addremove
767 adding a
774 adding a
768 $ hg ci -m "commit"
775 $ hg ci -m "commit"
769 $ cat > a.patch <<EOF
776 $ cat > a.patch <<EOF
770 > add a, b
777 > add a, b
771 > diff --git a/a b/a
778 > diff --git a/a b/a
772 > --- a/a
779 > --- a/a
773 > +++ b/a
780 > +++ b/a
774 > @@ -0,0 +1,1 @@
781 > @@ -0,0 +1,1 @@
775 > +a
782 > +a
776 > diff --git a/b b/b
783 > diff --git a/b b/b
777 > new file mode 100644
784 > new file mode 100644
778 > EOF
785 > EOF
779 $ hg import --no-commit a.patch
786 $ hg import --no-commit a.patch
780 applying a.patch
787 applying a.patch
781
788
782 apply a good patch followed by an empty patch (mainly to ensure
789 apply a good patch followed by an empty patch (mainly to ensure
783 that dirstate is *not* updated when import crashes)
790 that dirstate is *not* updated when import crashes)
784 $ hg update -q -C .
791 $ hg update -q -C .
785 $ rm b
792 $ rm b
786 $ touch empty.patch
793 $ touch empty.patch
787 $ hg import a.patch empty.patch
794 $ hg import a.patch empty.patch
788 applying a.patch
795 applying a.patch
789 applying empty.patch
796 applying empty.patch
790 transaction abort!
797 transaction abort!
791 rollback completed
798 rollback completed
792 abort: empty.patch: no diffs found
799 abort: empty.patch: no diffs found
793 [255]
800 [255]
794 $ hg tip --template '{rev} {desc|firstline}\n'
801 $ hg tip --template '{rev} {desc|firstline}\n'
795 0 commit
802 0 commit
796 $ hg -q status
803 $ hg -q status
797 M a
804 M a
798 $ cd ..
805 $ cd ..
799
806
800 create file when source is not /dev/null
807 create file when source is not /dev/null
801
808
802 $ cat > create.patch <<EOF
809 $ cat > create.patch <<EOF
803 > diff -Naur proj-orig/foo proj-new/foo
810 > diff -Naur proj-orig/foo proj-new/foo
804 > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
811 > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
805 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
812 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
806 > @@ -0,0 +1,1 @@
813 > @@ -0,0 +1,1 @@
807 > +a
814 > +a
808 > EOF
815 > EOF
809
816
810 some people have patches like the following too
817 some people have patches like the following too
811
818
812 $ cat > create2.patch <<EOF
819 $ cat > create2.patch <<EOF
813 > diff -Naur proj-orig/foo proj-new/foo
820 > diff -Naur proj-orig/foo proj-new/foo
814 > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
821 > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
815 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
822 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
816 > @@ -0,0 +1,1 @@
823 > @@ -0,0 +1,1 @@
817 > +a
824 > +a
818 > EOF
825 > EOF
819 $ hg init oddcreate
826 $ hg init oddcreate
820 $ cd oddcreate
827 $ cd oddcreate
821 $ hg import --no-commit ../create.patch
828 $ hg import --no-commit ../create.patch
822 applying ../create.patch
829 applying ../create.patch
823 $ cat foo
830 $ cat foo
824 a
831 a
825 $ rm foo
832 $ rm foo
826 $ hg revert foo
833 $ hg revert foo
827 $ hg import --no-commit ../create2.patch
834 $ hg import --no-commit ../create2.patch
828 applying ../create2.patch
835 applying ../create2.patch
829 $ cat foo
836 $ cat foo
830 a
837 a
831
838
832 $ cd ..
839 $ cd ..
833
840
834 Issue1859: first line mistaken for email headers
841 Issue1859: first line mistaken for email headers
835
842
836 $ hg init emailconfusion
843 $ hg init emailconfusion
837 $ cd emailconfusion
844 $ cd emailconfusion
838 $ cat > a.patch <<EOF
845 $ cat > a.patch <<EOF
839 > module: summary
846 > module: summary
840 >
847 >
841 > description
848 > description
842 >
849 >
843 >
850 >
844 > diff -r 000000000000 -r 9b4c1e343b55 test.txt
851 > diff -r 000000000000 -r 9b4c1e343b55 test.txt
845 > --- /dev/null
852 > --- /dev/null
846 > +++ b/a
853 > +++ b/a
847 > @@ -0,0 +1,1 @@
854 > @@ -0,0 +1,1 @@
848 > +a
855 > +a
849 > EOF
856 > EOF
850 $ hg import -d '0 0' a.patch
857 $ hg import -d '0 0' a.patch
851 applying a.patch
858 applying a.patch
852 $ hg parents -v
859 $ hg parents -v
853 changeset: 0:5a681217c0ad
860 changeset: 0:5a681217c0ad
854 tag: tip
861 tag: tip
855 user: test
862 user: test
856 date: Thu Jan 01 00:00:00 1970 +0000
863 date: Thu Jan 01 00:00:00 1970 +0000
857 files: a
864 files: a
858 description:
865 description:
859 module: summary
866 module: summary
860
867
861 description
868 description
862
869
863
870
864 $ cd ..
871 $ cd ..
865
872
866
873
867 in commit message
874 in commit message
868
875
869 $ hg init commitconfusion
876 $ hg init commitconfusion
870 $ cd commitconfusion
877 $ cd commitconfusion
871 $ cat > a.patch <<EOF
878 $ cat > a.patch <<EOF
872 > module: summary
879 > module: summary
873 >
880 >
874 > --- description
881 > --- description
875 >
882 >
876 > diff --git a/a b/a
883 > diff --git a/a b/a
877 > new file mode 100644
884 > new file mode 100644
878 > --- /dev/null
885 > --- /dev/null
879 > +++ b/a
886 > +++ b/a
880 > @@ -0,0 +1,1 @@
887 > @@ -0,0 +1,1 @@
881 > +a
888 > +a
882 > EOF
889 > EOF
883 > hg import -d '0 0' a.patch
890 > hg import -d '0 0' a.patch
884 > hg parents -v
891 > hg parents -v
885 > cd ..
892 > cd ..
886 >
893 >
887 > echo '% tricky header splitting'
894 > echo '% tricky header splitting'
888 > cat > trickyheaders.patch <<EOF
895 > cat > trickyheaders.patch <<EOF
889 > From: User A <user@a>
896 > From: User A <user@a>
890 > Subject: [PATCH] from: tricky!
897 > Subject: [PATCH] from: tricky!
891 >
898 >
892 > # HG changeset patch
899 > # HG changeset patch
893 > # User User B
900 > # User User B
894 > # Date 1266264441 18000
901 > # Date 1266264441 18000
895 > # Branch stable
902 > # Branch stable
896 > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
903 > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
897 > # Parent 0000000000000000000000000000000000000000
904 > # Parent 0000000000000000000000000000000000000000
898 > from: tricky!
905 > from: tricky!
899 >
906 >
900 > That is not a header.
907 > That is not a header.
901 >
908 >
902 > diff -r 000000000000 -r f2be6a1170ac foo
909 > diff -r 000000000000 -r f2be6a1170ac foo
903 > --- /dev/null
910 > --- /dev/null
904 > +++ b/foo
911 > +++ b/foo
905 > @@ -0,0 +1,1 @@
912 > @@ -0,0 +1,1 @@
906 > +foo
913 > +foo
907 > EOF
914 > EOF
908 applying a.patch
915 applying a.patch
909 changeset: 0:f34d9187897d
916 changeset: 0:f34d9187897d
910 tag: tip
917 tag: tip
911 user: test
918 user: test
912 date: Thu Jan 01 00:00:00 1970 +0000
919 date: Thu Jan 01 00:00:00 1970 +0000
913 files: a
920 files: a
914 description:
921 description:
915 module: summary
922 module: summary
916
923
917
924
918 % tricky header splitting
925 % tricky header splitting
919
926
920 $ hg init trickyheaders
927 $ hg init trickyheaders
921 $ cd trickyheaders
928 $ cd trickyheaders
922 $ hg import -d '0 0' ../trickyheaders.patch
929 $ hg import -d '0 0' ../trickyheaders.patch
923 applying ../trickyheaders.patch
930 applying ../trickyheaders.patch
924 $ hg export --git tip
931 $ hg export --git tip
925 # HG changeset patch
932 # HG changeset patch
926 # User User B
933 # User User B
927 # Date 0 0
934 # Date 0 0
928 # Thu Jan 01 00:00:00 1970 +0000
935 # Thu Jan 01 00:00:00 1970 +0000
929 # Node ID eb56ab91903632294ac504838508cb370c0901d2
936 # Node ID eb56ab91903632294ac504838508cb370c0901d2
930 # Parent 0000000000000000000000000000000000000000
937 # Parent 0000000000000000000000000000000000000000
931 from: tricky!
938 from: tricky!
932
939
933 That is not a header.
940 That is not a header.
934
941
935 diff --git a/foo b/foo
942 diff --git a/foo b/foo
936 new file mode 100644
943 new file mode 100644
937 --- /dev/null
944 --- /dev/null
938 +++ b/foo
945 +++ b/foo
939 @@ -0,0 +1,1 @@
946 @@ -0,0 +1,1 @@
940 +foo
947 +foo
941 $ cd ..
948 $ cd ..
942
949
943
950
944 Issue2102: hg export and hg import speak different languages
951 Issue2102: hg export and hg import speak different languages
945
952
946 $ hg init issue2102
953 $ hg init issue2102
947 $ cd issue2102
954 $ cd issue2102
948 $ mkdir -p src/cmd/gc
955 $ mkdir -p src/cmd/gc
949 $ touch src/cmd/gc/mksys.bash
956 $ touch src/cmd/gc/mksys.bash
950 $ hg ci -Am init
957 $ hg ci -Am init
951 adding src/cmd/gc/mksys.bash
958 adding src/cmd/gc/mksys.bash
952 $ hg import - <<EOF
959 $ hg import - <<EOF
953 > # HG changeset patch
960 > # HG changeset patch
954 > # User Rob Pike
961 > # User Rob Pike
955 > # Date 1216685449 25200
962 > # Date 1216685449 25200
956 > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
963 > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
957 > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
964 > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
958 > help management of empty pkg and lib directories in perforce
965 > help management of empty pkg and lib directories in perforce
959 >
966 >
960 > R=gri
967 > R=gri
961 > DELTA=4 (4 added, 0 deleted, 0 changed)
968 > DELTA=4 (4 added, 0 deleted, 0 changed)
962 > OCL=13328
969 > OCL=13328
963 > CL=13328
970 > CL=13328
964 >
971 >
965 > diff --git a/lib/place-holder b/lib/place-holder
972 > diff --git a/lib/place-holder b/lib/place-holder
966 > new file mode 100644
973 > new file mode 100644
967 > --- /dev/null
974 > --- /dev/null
968 > +++ b/lib/place-holder
975 > +++ b/lib/place-holder
969 > @@ -0,0 +1,2 @@
976 > @@ -0,0 +1,2 @@
970 > +perforce does not maintain empty directories.
977 > +perforce does not maintain empty directories.
971 > +this file helps.
978 > +this file helps.
972 > diff --git a/pkg/place-holder b/pkg/place-holder
979 > diff --git a/pkg/place-holder b/pkg/place-holder
973 > new file mode 100644
980 > new file mode 100644
974 > --- /dev/null
981 > --- /dev/null
975 > +++ b/pkg/place-holder
982 > +++ b/pkg/place-holder
976 > @@ -0,0 +1,2 @@
983 > @@ -0,0 +1,2 @@
977 > +perforce does not maintain empty directories.
984 > +perforce does not maintain empty directories.
978 > +this file helps.
985 > +this file helps.
979 > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
986 > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
980 > old mode 100644
987 > old mode 100644
981 > new mode 100755
988 > new mode 100755
982 > EOF
989 > EOF
983 applying patch from stdin
990 applying patch from stdin
984
991
985 #if execbit
992 #if execbit
986
993
987 $ hg sum
994 $ hg sum
988 parent: 1:d59915696727 tip
995 parent: 1:d59915696727 tip
989 help management of empty pkg and lib directories in perforce
996 help management of empty pkg and lib directories in perforce
990 branch: default
997 branch: default
991 commit: (clean)
998 commit: (clean)
992 update: (current)
999 update: (current)
993 phases: 2 draft
1000 phases: 2 draft
994
1001
995 $ hg diff --git -c tip
1002 $ hg diff --git -c tip
996 diff --git a/lib/place-holder b/lib/place-holder
1003 diff --git a/lib/place-holder b/lib/place-holder
997 new file mode 100644
1004 new file mode 100644
998 --- /dev/null
1005 --- /dev/null
999 +++ b/lib/place-holder
1006 +++ b/lib/place-holder
1000 @@ -0,0 +1,2 @@
1007 @@ -0,0 +1,2 @@
1001 +perforce does not maintain empty directories.
1008 +perforce does not maintain empty directories.
1002 +this file helps.
1009 +this file helps.
1003 diff --git a/pkg/place-holder b/pkg/place-holder
1010 diff --git a/pkg/place-holder b/pkg/place-holder
1004 new file mode 100644
1011 new file mode 100644
1005 --- /dev/null
1012 --- /dev/null
1006 +++ b/pkg/place-holder
1013 +++ b/pkg/place-holder
1007 @@ -0,0 +1,2 @@
1014 @@ -0,0 +1,2 @@
1008 +perforce does not maintain empty directories.
1015 +perforce does not maintain empty directories.
1009 +this file helps.
1016 +this file helps.
1010 diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1017 diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
1011 old mode 100644
1018 old mode 100644
1012 new mode 100755
1019 new mode 100755
1013
1020
1014 #else
1021 #else
1015
1022
1016 $ hg sum
1023 $ hg sum
1017 parent: 1:28f089cc9ccc tip
1024 parent: 1:28f089cc9ccc tip
1018 help management of empty pkg and lib directories in perforce
1025 help management of empty pkg and lib directories in perforce
1019 branch: default
1026 branch: default
1020 commit: (clean)
1027 commit: (clean)
1021 update: (current)
1028 update: (current)
1022 phases: 2 draft
1029 phases: 2 draft
1023
1030
1024 $ hg diff --git -c tip
1031 $ hg diff --git -c tip
1025 diff --git a/lib/place-holder b/lib/place-holder
1032 diff --git a/lib/place-holder b/lib/place-holder
1026 new file mode 100644
1033 new file mode 100644
1027 --- /dev/null
1034 --- /dev/null
1028 +++ b/lib/place-holder
1035 +++ b/lib/place-holder
1029 @@ -0,0 +1,2 @@
1036 @@ -0,0 +1,2 @@
1030 +perforce does not maintain empty directories.
1037 +perforce does not maintain empty directories.
1031 +this file helps.
1038 +this file helps.
1032 diff --git a/pkg/place-holder b/pkg/place-holder
1039 diff --git a/pkg/place-holder b/pkg/place-holder
1033 new file mode 100644
1040 new file mode 100644
1034 --- /dev/null
1041 --- /dev/null
1035 +++ b/pkg/place-holder
1042 +++ b/pkg/place-holder
1036 @@ -0,0 +1,2 @@
1043 @@ -0,0 +1,2 @@
1037 +perforce does not maintain empty directories.
1044 +perforce does not maintain empty directories.
1038 +this file helps.
1045 +this file helps.
1039
1046
1040 /* The mode change for mksys.bash is missing here, because on platforms */
1047 /* The mode change for mksys.bash is missing here, because on platforms */
1041 /* that don't support execbits, mode changes in patches are ignored when */
1048 /* that don't support execbits, mode changes in patches are ignored when */
1042 /* they are imported. This is obviously also the reason for why the hash */
1049 /* they are imported. This is obviously also the reason for why the hash */
1043 /* in the created changeset is different to the one you see above the */
1050 /* in the created changeset is different to the one you see above the */
1044 /* #else clause */
1051 /* #else clause */
1045
1052
1046 #endif
1053 #endif
1047 $ cd ..
1054 $ cd ..
1048
1055
1049
1056
1050 diff lines looking like headers
1057 diff lines looking like headers
1051
1058
1052 $ hg init difflineslikeheaders
1059 $ hg init difflineslikeheaders
1053 $ cd difflineslikeheaders
1060 $ cd difflineslikeheaders
1054 $ echo a >a
1061 $ echo a >a
1055 $ echo b >b
1062 $ echo b >b
1056 $ echo c >c
1063 $ echo c >c
1057 $ hg ci -Am1
1064 $ hg ci -Am1
1058 adding a
1065 adding a
1059 adding b
1066 adding b
1060 adding c
1067 adding c
1061
1068
1062 $ echo "key: value" >>a
1069 $ echo "key: value" >>a
1063 $ echo "key: value" >>b
1070 $ echo "key: value" >>b
1064 $ echo "foo" >>c
1071 $ echo "foo" >>c
1065 $ hg ci -m2
1072 $ hg ci -m2
1066
1073
1067 $ hg up -C 0
1074 $ hg up -C 0
1068 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1075 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069 $ hg diff --git -c1 >want
1076 $ hg diff --git -c1 >want
1070 $ hg diff -c1 | hg import --no-commit -
1077 $ hg diff -c1 | hg import --no-commit -
1071 applying patch from stdin
1078 applying patch from stdin
1072 $ hg diff --git >have
1079 $ hg diff --git >have
1073 $ diff want have
1080 $ diff want have
1074 $ cd ..
1081 $ cd ..
1075
1082
1076 import a unified diff with no lines of context (diff -U0)
1083 import a unified diff with no lines of context (diff -U0)
1077
1084
1078 $ hg init diffzero
1085 $ hg init diffzero
1079 $ cd diffzero
1086 $ cd diffzero
1080 $ cat > f << EOF
1087 $ cat > f << EOF
1081 > c2
1088 > c2
1082 > c4
1089 > c4
1083 > c5
1090 > c5
1084 > EOF
1091 > EOF
1085 $ hg commit -Am0
1092 $ hg commit -Am0
1086 adding f
1093 adding f
1087
1094
1088 $ hg import --no-commit - << EOF
1095 $ hg import --no-commit - << EOF
1089 > # HG changeset patch
1096 > # HG changeset patch
1090 > # User test
1097 > # User test
1091 > # Date 0 0
1098 > # Date 0 0
1092 > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
1099 > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
1093 > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
1100 > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
1094 > 1
1101 > 1
1095 > diff -r 8679a12a975b -r f4974ab632f3 f
1102 > diff -r 8679a12a975b -r f4974ab632f3 f
1096 > --- a/f Thu Jan 01 00:00:00 1970 +0000
1103 > --- a/f Thu Jan 01 00:00:00 1970 +0000
1097 > +++ b/f Thu Jan 01 00:00:00 1970 +0000
1104 > +++ b/f Thu Jan 01 00:00:00 1970 +0000
1098 > @@ -0,0 +1,1 @@
1105 > @@ -0,0 +1,1 @@
1099 > +c1
1106 > +c1
1100 > @@ -1,0 +3,1 @@
1107 > @@ -1,0 +3,1 @@
1101 > +c3
1108 > +c3
1102 > @@ -3,1 +4,0 @@
1109 > @@ -3,1 +4,0 @@
1103 > -c5
1110 > -c5
1104 > EOF
1111 > EOF
1105 applying patch from stdin
1112 applying patch from stdin
1106
1113
1107 $ cat f
1114 $ cat f
1108 c1
1115 c1
1109 c2
1116 c2
1110 c3
1117 c3
1111 c4
1118 c4
1112
1119
1113 $ cd ..
1120 $ cd ..
1114
1121
1115 no segfault while importing a unified diff which start line is zero but chunk
1122 no segfault while importing a unified diff which start line is zero but chunk
1116 size is non-zero
1123 size is non-zero
1117
1124
1118 $ hg init startlinezero
1125 $ hg init startlinezero
1119 $ cd startlinezero
1126 $ cd startlinezero
1120 $ echo foo > foo
1127 $ echo foo > foo
1121 $ hg commit -Amfoo
1128 $ hg commit -Amfoo
1122 adding foo
1129 adding foo
1123
1130
1124 $ hg import --no-commit - << EOF
1131 $ hg import --no-commit - << EOF
1125 > diff a/foo b/foo
1132 > diff a/foo b/foo
1126 > --- a/foo
1133 > --- a/foo
1127 > +++ b/foo
1134 > +++ b/foo
1128 > @@ -0,1 +0,1 @@
1135 > @@ -0,1 +0,1 @@
1129 > foo
1136 > foo
1130 > EOF
1137 > EOF
1131 applying patch from stdin
1138 applying patch from stdin
1132
1139
1133 $ cd ..
1140 $ cd ..
1134
1141
1135 Test corner case involving fuzz and skew
1142 Test corner case involving fuzz and skew
1136
1143
1137 $ hg init morecornercases
1144 $ hg init morecornercases
1138 $ cd morecornercases
1145 $ cd morecornercases
1139
1146
1140 $ cat > 01-no-context-beginning-of-file.diff <<EOF
1147 $ cat > 01-no-context-beginning-of-file.diff <<EOF
1141 > diff --git a/a b/a
1148 > diff --git a/a b/a
1142 > --- a/a
1149 > --- a/a
1143 > +++ b/a
1150 > +++ b/a
1144 > @@ -1,0 +1,1 @@
1151 > @@ -1,0 +1,1 @@
1145 > +line
1152 > +line
1146 > EOF
1153 > EOF
1147
1154
1148 $ cat > 02-no-context-middle-of-file.diff <<EOF
1155 $ cat > 02-no-context-middle-of-file.diff <<EOF
1149 > diff --git a/a b/a
1156 > diff --git a/a b/a
1150 > --- a/a
1157 > --- a/a
1151 > +++ b/a
1158 > +++ b/a
1152 > @@ -1,1 +1,1 @@
1159 > @@ -1,1 +1,1 @@
1153 > -2
1160 > -2
1154 > +add some skew
1161 > +add some skew
1155 > @@ -2,0 +2,1 @@
1162 > @@ -2,0 +2,1 @@
1156 > +line
1163 > +line
1157 > EOF
1164 > EOF
1158
1165
1159 $ cat > 03-no-context-end-of-file.diff <<EOF
1166 $ cat > 03-no-context-end-of-file.diff <<EOF
1160 > diff --git a/a b/a
1167 > diff --git a/a b/a
1161 > --- a/a
1168 > --- a/a
1162 > +++ b/a
1169 > +++ b/a
1163 > @@ -10,0 +10,1 @@
1170 > @@ -10,0 +10,1 @@
1164 > +line
1171 > +line
1165 > EOF
1172 > EOF
1166
1173
1167 $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
1174 $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
1168 > diff --git a/a b/a
1175 > diff --git a/a b/a
1169 > --- a/a
1176 > --- a/a
1170 > +++ b/a
1177 > +++ b/a
1171 > @@ -1,1 +1,1 @@
1178 > @@ -1,1 +1,1 @@
1172 > -2
1179 > -2
1173 > +add some skew
1180 > +add some skew
1174 > @@ -2,2 +2,3 @@
1181 > @@ -2,2 +2,3 @@
1175 > not matching, should fuzz
1182 > not matching, should fuzz
1176 > ... a bit
1183 > ... a bit
1177 > +line
1184 > +line
1178 > EOF
1185 > EOF
1179
1186
1180 $ cat > a <<EOF
1187 $ cat > a <<EOF
1181 > 1
1188 > 1
1182 > 2
1189 > 2
1183 > 3
1190 > 3
1184 > 4
1191 > 4
1185 > EOF
1192 > EOF
1186 $ hg ci -Am adda a
1193 $ hg ci -Am adda a
1187 $ for p in *.diff; do
1194 $ for p in *.diff; do
1188 > hg import -v --no-commit $p
1195 > hg import -v --no-commit $p
1189 > cat a
1196 > cat a
1190 > hg revert -aqC a
1197 > hg revert -aqC a
1191 > # patch -p1 < $p
1198 > # patch -p1 < $p
1192 > # cat a
1199 > # cat a
1193 > # hg revert -aC a
1200 > # hg revert -aC a
1194 > done
1201 > done
1195 applying 01-no-context-beginning-of-file.diff
1202 applying 01-no-context-beginning-of-file.diff
1196 patching file a
1203 patching file a
1197 applied to working directory
1204 applied to working directory
1198 1
1205 1
1199 line
1206 line
1200 2
1207 2
1201 3
1208 3
1202 4
1209 4
1203 applying 02-no-context-middle-of-file.diff
1210 applying 02-no-context-middle-of-file.diff
1204 patching file a
1211 patching file a
1205 Hunk #1 succeeded at 2 (offset 1 lines).
1212 Hunk #1 succeeded at 2 (offset 1 lines).
1206 Hunk #2 succeeded at 4 (offset 1 lines).
1213 Hunk #2 succeeded at 4 (offset 1 lines).
1207 applied to working directory
1214 applied to working directory
1208 1
1215 1
1209 add some skew
1216 add some skew
1210 3
1217 3
1211 line
1218 line
1212 4
1219 4
1213 applying 03-no-context-end-of-file.diff
1220 applying 03-no-context-end-of-file.diff
1214 patching file a
1221 patching file a
1215 Hunk #1 succeeded at 5 (offset -6 lines).
1222 Hunk #1 succeeded at 5 (offset -6 lines).
1216 applied to working directory
1223 applied to working directory
1217 1
1224 1
1218 2
1225 2
1219 3
1226 3
1220 4
1227 4
1221 line
1228 line
1222 applying 04-middle-of-file-completely-fuzzed.diff
1229 applying 04-middle-of-file-completely-fuzzed.diff
1223 patching file a
1230 patching file a
1224 Hunk #1 succeeded at 2 (offset 1 lines).
1231 Hunk #1 succeeded at 2 (offset 1 lines).
1225 Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
1232 Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
1226 applied to working directory
1233 applied to working directory
1227 1
1234 1
1228 add some skew
1235 add some skew
1229 3
1236 3
1230 4
1237 4
1231 line
1238 line
1232 $ cd ..
1239 $ cd ..
1233
1240
1234 Test partial application
1241 Test partial application
1235 ------------------------
1242 ------------------------
1236
1243
1237 prepare a stack of patches depending on each other
1244 prepare a stack of patches depending on each other
1238
1245
1239 $ hg init partial
1246 $ hg init partial
1240 $ cd partial
1247 $ cd partial
1241 $ cat << EOF > a
1248 $ cat << EOF > a
1242 > one
1249 > one
1243 > two
1250 > two
1244 > three
1251 > three
1245 > four
1252 > four
1246 > five
1253 > five
1247 > six
1254 > six
1248 > seven
1255 > seven
1249 > EOF
1256 > EOF
1250 $ hg add a
1257 $ hg add a
1251 $ echo 'b' > b
1258 $ echo 'b' > b
1252 $ hg add b
1259 $ hg add b
1253 $ hg commit -m 'initial' -u Babar
1260 $ hg commit -m 'initial' -u Babar
1254 $ cat << EOF > a
1261 $ cat << EOF > a
1255 > one
1262 > one
1256 > two
1263 > two
1257 > 3
1264 > 3
1258 > four
1265 > four
1259 > five
1266 > five
1260 > six
1267 > six
1261 > seven
1268 > seven
1262 > EOF
1269 > EOF
1263 $ hg commit -m 'three' -u Celeste
1270 $ hg commit -m 'three' -u Celeste
1264 $ cat << EOF > a
1271 $ cat << EOF > a
1265 > one
1272 > one
1266 > two
1273 > two
1267 > 3
1274 > 3
1268 > 4
1275 > 4
1269 > five
1276 > five
1270 > six
1277 > six
1271 > seven
1278 > seven
1272 > EOF
1279 > EOF
1273 $ hg commit -m 'four' -u Rataxes
1280 $ hg commit -m 'four' -u Rataxes
1274 $ cat << EOF > a
1281 $ cat << EOF > a
1275 > one
1282 > one
1276 > two
1283 > two
1277 > 3
1284 > 3
1278 > 4
1285 > 4
1279 > 5
1286 > 5
1280 > six
1287 > six
1281 > seven
1288 > seven
1282 > EOF
1289 > EOF
1283 $ echo bb >> b
1290 $ echo bb >> b
1284 $ hg commit -m 'five' -u Arthur
1291 $ hg commit -m 'five' -u Arthur
1285 $ echo 'Babar' > jungle
1292 $ echo 'Babar' > jungle
1286 $ hg add jungle
1293 $ hg add jungle
1287 $ hg ci -m 'jungle' -u Zephir
1294 $ hg ci -m 'jungle' -u Zephir
1288 $ echo 'Celeste' >> jungle
1295 $ echo 'Celeste' >> jungle
1289 $ hg ci -m 'extended jungle' -u Cornelius
1296 $ hg ci -m 'extended jungle' -u Cornelius
1290 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1297 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1291 @ extended jungle [Cornelius] 1: +1/-0
1298 @ extended jungle [Cornelius] 1: +1/-0
1292 |
1299 |
1293 o jungle [Zephir] 1: +1/-0
1300 o jungle [Zephir] 1: +1/-0
1294 |
1301 |
1295 o five [Arthur] 2: +2/-1
1302 o five [Arthur] 2: +2/-1
1296 |
1303 |
1297 o four [Rataxes] 1: +1/-1
1304 o four [Rataxes] 1: +1/-1
1298 |
1305 |
1299 o three [Celeste] 1: +1/-1
1306 o three [Celeste] 1: +1/-1
1300 |
1307 |
1301 o initial [Babar] 2: +8/-0
1308 o initial [Babar] 2: +8/-0
1302
1309
1303
1310
1304 Importing with some success and some errors:
1311 Importing with some success and some errors:
1305
1312
1306 $ hg update --rev 'desc(initial)'
1313 $ hg update --rev 'desc(initial)'
1307 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1314 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1308 $ hg export --rev 'desc(five)' | hg import --partial -
1315 $ hg export --rev 'desc(five)' | hg import --partial -
1309 applying patch from stdin
1316 applying patch from stdin
1310 patching file a
1317 patching file a
1311 Hunk #1 FAILED at 1
1318 Hunk #1 FAILED at 1
1312 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1319 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1313 patch applied partially
1320 patch applied partially
1314 (fix the .rej files and run `hg commit --amend`)
1321 (fix the .rej files and run `hg commit --amend`)
1315 [1]
1322 [1]
1316
1323
1317 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1324 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1318 @ five [Arthur] 1: +1/-0
1325 @ five [Arthur] 1: +1/-0
1319 |
1326 |
1320 | o extended jungle [Cornelius] 1: +1/-0
1327 | o extended jungle [Cornelius] 1: +1/-0
1321 | |
1328 | |
1322 | o jungle [Zephir] 1: +1/-0
1329 | o jungle [Zephir] 1: +1/-0
1323 | |
1330 | |
1324 | o five [Arthur] 2: +2/-1
1331 | o five [Arthur] 2: +2/-1
1325 | |
1332 | |
1326 | o four [Rataxes] 1: +1/-1
1333 | o four [Rataxes] 1: +1/-1
1327 | |
1334 | |
1328 | o three [Celeste] 1: +1/-1
1335 | o three [Celeste] 1: +1/-1
1329 |/
1336 |/
1330 o initial [Babar] 2: +8/-0
1337 o initial [Babar] 2: +8/-0
1331
1338
1332 $ hg export
1339 $ hg export
1333 # HG changeset patch
1340 # HG changeset patch
1334 # User Arthur
1341 # User Arthur
1335 # Date 0 0
1342 # Date 0 0
1336 # Thu Jan 01 00:00:00 1970 +0000
1343 # Thu Jan 01 00:00:00 1970 +0000
1337 # Node ID 26e6446bb2526e2be1037935f5fca2b2706f1509
1344 # Node ID 26e6446bb2526e2be1037935f5fca2b2706f1509
1338 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1345 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1339 five
1346 five
1340
1347
1341 diff -r 8e4f0351909e -r 26e6446bb252 b
1348 diff -r 8e4f0351909e -r 26e6446bb252 b
1342 --- a/b Thu Jan 01 00:00:00 1970 +0000
1349 --- a/b Thu Jan 01 00:00:00 1970 +0000
1343 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1350 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1344 @@ -1,1 +1,2 @@
1351 @@ -1,1 +1,2 @@
1345 b
1352 b
1346 +bb
1353 +bb
1347 $ hg status -c .
1354 $ hg status -c .
1348 C a
1355 C a
1349 C b
1356 C b
1350 $ ls
1357 $ ls
1351 a
1358 a
1352 a.rej
1359 a.rej
1353 b
1360 b
1354
1361
1355 Importing with zero success:
1362 Importing with zero success:
1356
1363
1357 $ hg update --rev 'desc(initial)'
1364 $ hg update --rev 'desc(initial)'
1358 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1359 $ hg export --rev 'desc(four)' | hg import --partial -
1366 $ hg export --rev 'desc(four)' | hg import --partial -
1360 applying patch from stdin
1367 applying patch from stdin
1361 patching file a
1368 patching file a
1362 Hunk #1 FAILED at 0
1369 Hunk #1 FAILED at 0
1363 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1370 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1364 patch applied partially
1371 patch applied partially
1365 (fix the .rej files and run `hg commit --amend`)
1372 (fix the .rej files and run `hg commit --amend`)
1366 [1]
1373 [1]
1367
1374
1368 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1375 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1369 @ four [Rataxes] 0: +0/-0
1376 @ four [Rataxes] 0: +0/-0
1370 |
1377 |
1371 | o five [Arthur] 1: +1/-0
1378 | o five [Arthur] 1: +1/-0
1372 |/
1379 |/
1373 | o extended jungle [Cornelius] 1: +1/-0
1380 | o extended jungle [Cornelius] 1: +1/-0
1374 | |
1381 | |
1375 | o jungle [Zephir] 1: +1/-0
1382 | o jungle [Zephir] 1: +1/-0
1376 | |
1383 | |
1377 | o five [Arthur] 2: +2/-1
1384 | o five [Arthur] 2: +2/-1
1378 | |
1385 | |
1379 | o four [Rataxes] 1: +1/-1
1386 | o four [Rataxes] 1: +1/-1
1380 | |
1387 | |
1381 | o three [Celeste] 1: +1/-1
1388 | o three [Celeste] 1: +1/-1
1382 |/
1389 |/
1383 o initial [Babar] 2: +8/-0
1390 o initial [Babar] 2: +8/-0
1384
1391
1385 $ hg export
1392 $ hg export
1386 # HG changeset patch
1393 # HG changeset patch
1387 # User Rataxes
1394 # User Rataxes
1388 # Date 0 0
1395 # Date 0 0
1389 # Thu Jan 01 00:00:00 1970 +0000
1396 # Thu Jan 01 00:00:00 1970 +0000
1390 # Node ID cb9b1847a74d9ad52e93becaf14b98dbcc274e1e
1397 # Node ID cb9b1847a74d9ad52e93becaf14b98dbcc274e1e
1391 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1398 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1392 four
1399 four
1393
1400
1394 $ hg status -c .
1401 $ hg status -c .
1395 C a
1402 C a
1396 C b
1403 C b
1397 $ ls
1404 $ ls
1398 a
1405 a
1399 a.rej
1406 a.rej
1400 b
1407 b
1401
1408
1402 Importing with unknown file:
1409 Importing with unknown file:
1403
1410
1404 $ hg update --rev 'desc(initial)'
1411 $ hg update --rev 'desc(initial)'
1405 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1412 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1406 $ hg export --rev 'desc("extended jungle")' | hg import --partial -
1413 $ hg export --rev 'desc("extended jungle")' | hg import --partial -
1407 applying patch from stdin
1414 applying patch from stdin
1408 unable to find 'jungle' for patching
1415 unable to find 'jungle' for patching
1409 1 out of 1 hunks FAILED -- saving rejects to file jungle.rej
1416 1 out of 1 hunks FAILED -- saving rejects to file jungle.rej
1410 patch applied partially
1417 patch applied partially
1411 (fix the .rej files and run `hg commit --amend`)
1418 (fix the .rej files and run `hg commit --amend`)
1412 [1]
1419 [1]
1413
1420
1414 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1421 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1415 @ extended jungle [Cornelius] 0: +0/-0
1422 @ extended jungle [Cornelius] 0: +0/-0
1416 |
1423 |
1417 | o four [Rataxes] 0: +0/-0
1424 | o four [Rataxes] 0: +0/-0
1418 |/
1425 |/
1419 | o five [Arthur] 1: +1/-0
1426 | o five [Arthur] 1: +1/-0
1420 |/
1427 |/
1421 | o extended jungle [Cornelius] 1: +1/-0
1428 | o extended jungle [Cornelius] 1: +1/-0
1422 | |
1429 | |
1423 | o jungle [Zephir] 1: +1/-0
1430 | o jungle [Zephir] 1: +1/-0
1424 | |
1431 | |
1425 | o five [Arthur] 2: +2/-1
1432 | o five [Arthur] 2: +2/-1
1426 | |
1433 | |
1427 | o four [Rataxes] 1: +1/-1
1434 | o four [Rataxes] 1: +1/-1
1428 | |
1435 | |
1429 | o three [Celeste] 1: +1/-1
1436 | o three [Celeste] 1: +1/-1
1430 |/
1437 |/
1431 o initial [Babar] 2: +8/-0
1438 o initial [Babar] 2: +8/-0
1432
1439
1433 $ hg export
1440 $ hg export
1434 # HG changeset patch
1441 # HG changeset patch
1435 # User Cornelius
1442 # User Cornelius
1436 # Date 0 0
1443 # Date 0 0
1437 # Thu Jan 01 00:00:00 1970 +0000
1444 # Thu Jan 01 00:00:00 1970 +0000
1438 # Node ID 1fb1f86bef43c5a75918178f8d23c29fb0a7398d
1445 # Node ID 1fb1f86bef43c5a75918178f8d23c29fb0a7398d
1439 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1446 # Parent 8e4f0351909eae6b9cf68c2c076cb54c42b54b2e
1440 extended jungle
1447 extended jungle
1441
1448
1442 $ hg status -c .
1449 $ hg status -c .
1443 C a
1450 C a
1444 C b
1451 C b
1445 $ ls
1452 $ ls
1446 a
1453 a
1447 a.rej
1454 a.rej
1448 b
1455 b
1449 jungle.rej
1456 jungle.rej
1450
1457
1451 Importing multiple failing patches:
1458 Importing multiple failing patches:
1452
1459
1453 $ hg update --rev 'desc(initial)'
1460 $ hg update --rev 'desc(initial)'
1454 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1461 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1455 $ echo 'B' > b # just to make another commit
1462 $ echo 'B' > b # just to make another commit
1456 $ hg commit -m "a new base"
1463 $ hg commit -m "a new base"
1457 created new head
1464 created new head
1458 $ hg export --rev 'desc("four") + desc("extended jungle")' | hg import --partial -
1465 $ hg export --rev 'desc("four") + desc("extended jungle")' | hg import --partial -
1459 applying patch from stdin
1466 applying patch from stdin
1460 patching file a
1467 patching file a
1461 Hunk #1 FAILED at 0
1468 Hunk #1 FAILED at 0
1462 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1469 1 out of 1 hunks FAILED -- saving rejects to file a.rej
1463 patch applied partially
1470 patch applied partially
1464 (fix the .rej files and run `hg commit --amend`)
1471 (fix the .rej files and run `hg commit --amend`)
1465 [1]
1472 [1]
1466 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1473 $ hg log -G --template '{desc|firstline} [{author}] {diffstat}\n'
1467 @ four [Rataxes] 0: +0/-0
1474 @ four [Rataxes] 0: +0/-0
1468 |
1475 |
1469 o a new base [test] 1: +1/-1
1476 o a new base [test] 1: +1/-1
1470 |
1477 |
1471 | o extended jungle [Cornelius] 0: +0/-0
1478 | o extended jungle [Cornelius] 0: +0/-0
1472 |/
1479 |/
1473 | o four [Rataxes] 0: +0/-0
1480 | o four [Rataxes] 0: +0/-0
1474 |/
1481 |/
1475 | o five [Arthur] 1: +1/-0
1482 | o five [Arthur] 1: +1/-0
1476 |/
1483 |/
1477 | o extended jungle [Cornelius] 1: +1/-0
1484 | o extended jungle [Cornelius] 1: +1/-0
1478 | |
1485 | |
1479 | o jungle [Zephir] 1: +1/-0
1486 | o jungle [Zephir] 1: +1/-0
1480 | |
1487 | |
1481 | o five [Arthur] 2: +2/-1
1488 | o five [Arthur] 2: +2/-1
1482 | |
1489 | |
1483 | o four [Rataxes] 1: +1/-1
1490 | o four [Rataxes] 1: +1/-1
1484 | |
1491 | |
1485 | o three [Celeste] 1: +1/-1
1492 | o three [Celeste] 1: +1/-1
1486 |/
1493 |/
1487 o initial [Babar] 2: +8/-0
1494 o initial [Babar] 2: +8/-0
1488
1495
1489 $ hg export
1496 $ hg export
1490 # HG changeset patch
1497 # HG changeset patch
1491 # User Rataxes
1498 # User Rataxes
1492 # Date 0 0
1499 # Date 0 0
1493 # Thu Jan 01 00:00:00 1970 +0000
1500 # Thu Jan 01 00:00:00 1970 +0000
1494 # Node ID a9d7b6d0ffbb4eb12b7d5939250fcd42e8930a1d
1501 # Node ID a9d7b6d0ffbb4eb12b7d5939250fcd42e8930a1d
1495 # Parent f59f8d2e95a8ca5b1b4ca64320140da85f3b44fd
1502 # Parent f59f8d2e95a8ca5b1b4ca64320140da85f3b44fd
1496 four
1503 four
1497
1504
1498 $ hg status -c .
1505 $ hg status -c .
1499 C a
1506 C a
1500 C b
1507 C b
General Comments 0
You need to be logged in to leave comments. Login now