##// END OF EJS Templates
eol: fix update - don't use and apply removed .hgeol patterns...
Mads Kiilerich -
r43476:dfaa477e default
parent child Browse files
Show More
@@ -1,468 +1,474
1 1 """automatically manage newlines in repository files
2 2
3 3 This extension allows you to manage the type of line endings (CRLF or
4 4 LF) that are used in the repository and in the local working
5 5 directory. That way you can get CRLF line endings on Windows and LF on
6 6 Unix/Mac, thereby letting everybody use their OS native line endings.
7 7
8 8 The extension reads its configuration from a versioned ``.hgeol``
9 9 configuration file found in the root of the working directory. The
10 10 ``.hgeol`` file use the same syntax as all other Mercurial
11 11 configuration files. It uses two sections, ``[patterns]`` and
12 12 ``[repository]``.
13 13
14 14 The ``[patterns]`` section specifies how line endings should be
15 15 converted between the working directory and the repository. The format is
16 16 specified by a file pattern. The first match is used, so put more
17 17 specific patterns first. The available line endings are ``LF``,
18 18 ``CRLF``, and ``BIN``.
19 19
20 20 Files with the declared format of ``CRLF`` or ``LF`` are always
21 21 checked out and stored in the repository in that format and files
22 22 declared to be binary (``BIN``) are left unchanged. Additionally,
23 23 ``native`` is an alias for checking out in the platform's default line
24 24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
25 25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
26 26 default behavior; it is only needed if you need to override a later,
27 27 more general pattern.
28 28
29 29 The optional ``[repository]`` section specifies the line endings to
30 30 use for files stored in the repository. It has a single setting,
31 31 ``native``, which determines the storage line endings for files
32 32 declared as ``native`` in the ``[patterns]`` section. It can be set to
33 33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
34 34 that on Windows, files configured as ``native`` (``CRLF`` by default)
35 35 will be converted to ``LF`` when stored in the repository. Files
36 36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
37 37 are always stored as-is in the repository.
38 38
39 39 Example versioned ``.hgeol`` file::
40 40
41 41 [patterns]
42 42 **.py = native
43 43 **.vcproj = CRLF
44 44 **.txt = native
45 45 Makefile = LF
46 46 **.jpg = BIN
47 47
48 48 [repository]
49 49 native = LF
50 50
51 51 .. note::
52 52
53 53 The rules will first apply when files are touched in the working
54 54 directory, e.g. by updating to null and back to tip to touch all files.
55 55
56 56 The extension uses an optional ``[eol]`` section read from both the
57 57 normal Mercurial configuration files and the ``.hgeol`` file, with the
58 58 latter overriding the former. You can use that section to control the
59 59 overall behavior. There are three settings:
60 60
61 61 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
62 62 ``CRLF`` to override the default interpretation of ``native`` for
63 63 checkout. This can be used with :hg:`archive` on Unix, say, to
64 64 generate an archive where files have line endings for Windows.
65 65
66 66 - ``eol.only-consistent`` (default True) can be set to False to make
67 67 the extension convert files with inconsistent EOLs. Inconsistent
68 68 means that there is both ``CRLF`` and ``LF`` present in the file.
69 69 Such files are normally not touched under the assumption that they
70 70 have mixed EOLs on purpose.
71 71
72 72 - ``eol.fix-trailing-newline`` (default False) can be set to True to
73 73 ensure that converted files end with a EOL character (either ``\\n``
74 74 or ``\\r\\n`` as per the configured patterns).
75 75
76 76 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
77 77 like the deprecated win32text extension does. This means that you can
78 78 disable win32text and enable eol and your filters will still work. You
79 79 only need to these filters until you have prepared a ``.hgeol`` file.
80 80
81 81 The ``win32text.forbid*`` hooks provided by the win32text extension
82 82 have been unified into a single hook named ``eol.checkheadshook``. The
83 83 hook will lookup the expected line endings from the ``.hgeol`` file,
84 84 which means you must migrate to a ``.hgeol`` file first before using
85 85 the hook. ``eol.checkheadshook`` only checks heads, intermediate
86 86 invalid revisions will be pushed. To forbid them completely, use the
87 87 ``eol.checkallhook`` hook. These hooks are best used as
88 88 ``pretxnchangegroup`` hooks.
89 89
90 90 See :hg:`help patterns` for more information about the glob patterns
91 91 used.
92 92 """
93 93
94 94 from __future__ import absolute_import
95 95
96 96 import os
97 97 import re
98 98 from mercurial.i18n import _
99 99 from mercurial import (
100 100 config,
101 101 error as errormod,
102 102 extensions,
103 103 match,
104 104 pycompat,
105 105 registrar,
106 106 scmutil,
107 107 util,
108 108 )
109 109 from mercurial.utils import stringutil
110 110
111 111 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
112 112 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
113 113 # be specifying the version(s) of Mercurial they are tested with, or
114 114 # leave the attribute unspecified.
115 115 testedwith = b'ships-with-hg-core'
116 116
117 117 configtable = {}
118 118 configitem = registrar.configitem(configtable)
119 119
120 120 configitem(
121 121 b'eol', b'fix-trailing-newline', default=False,
122 122 )
123 123 configitem(
124 124 b'eol', b'native', default=pycompat.oslinesep,
125 125 )
126 126 configitem(
127 127 b'eol', b'only-consistent', default=True,
128 128 )
129 129
130 130 # Matches a lone LF, i.e., one that is not part of CRLF.
131 131 singlelf = re.compile(b'(^|[^\r])\n')
132 132
133 133
134 134 def inconsistenteol(data):
135 135 return b'\r\n' in data and singlelf.search(data)
136 136
137 137
138 138 def tolf(s, params, ui, **kwargs):
139 139 """Filter to convert to LF EOLs."""
140 140 if stringutil.binary(s):
141 141 return s
142 142 if ui.configbool(b'eol', b'only-consistent') and inconsistenteol(s):
143 143 return s
144 144 if (
145 145 ui.configbool(b'eol', b'fix-trailing-newline')
146 146 and s
147 147 and not s.endswith(b'\n')
148 148 ):
149 149 s = s + b'\n'
150 150 return util.tolf(s)
151 151
152 152
153 153 def tocrlf(s, params, ui, **kwargs):
154 154 """Filter to convert to CRLF EOLs."""
155 155 if stringutil.binary(s):
156 156 return s
157 157 if ui.configbool(b'eol', b'only-consistent') and inconsistenteol(s):
158 158 return s
159 159 if (
160 160 ui.configbool(b'eol', b'fix-trailing-newline')
161 161 and s
162 162 and not s.endswith(b'\n')
163 163 ):
164 164 s = s + b'\n'
165 165 return util.tocrlf(s)
166 166
167 167
168 168 def isbinary(s, params, ui, **kwargs):
169 169 """Filter to do nothing with the file."""
170 170 return s
171 171
172 172
173 173 filters = {
174 174 b'to-lf': tolf,
175 175 b'to-crlf': tocrlf,
176 176 b'is-binary': isbinary,
177 177 # The following provide backwards compatibility with win32text
178 178 b'cleverencode:': tolf,
179 179 b'cleverdecode:': tocrlf,
180 180 }
181 181
182 182
183 183 class eolfile(object):
184 184 def __init__(self, ui, root, data):
185 185 self._decode = {
186 186 b'LF': b'to-lf',
187 187 b'CRLF': b'to-crlf',
188 188 b'BIN': b'is-binary',
189 189 }
190 190 self._encode = {
191 191 b'LF': b'to-lf',
192 192 b'CRLF': b'to-crlf',
193 193 b'BIN': b'is-binary',
194 194 }
195 195
196 196 self.cfg = config.config()
197 197 # Our files should not be touched. The pattern must be
198 198 # inserted first override a '** = native' pattern.
199 199 self.cfg.set(b'patterns', b'.hg*', b'BIN', b'eol')
200 200 # We can then parse the user's patterns.
201 201 self.cfg.parse(b'.hgeol', data)
202 202
203 203 isrepolf = self.cfg.get(b'repository', b'native') != b'CRLF'
204 204 self._encode[b'NATIVE'] = isrepolf and b'to-lf' or b'to-crlf'
205 205 iswdlf = ui.config(b'eol', b'native') in (b'LF', b'\n')
206 206 self._decode[b'NATIVE'] = iswdlf and b'to-lf' or b'to-crlf'
207 207
208 208 include = []
209 209 exclude = []
210 210 self.patterns = []
211 211 for pattern, style in self.cfg.items(b'patterns'):
212 212 key = style.upper()
213 213 if key == b'BIN':
214 214 exclude.append(pattern)
215 215 else:
216 216 include.append(pattern)
217 217 m = match.match(root, b'', [pattern])
218 218 self.patterns.append((pattern, key, m))
219 219 # This will match the files for which we need to care
220 220 # about inconsistent newlines.
221 221 self.match = match.match(root, b'', [], include, exclude)
222 222
223 223 def copytoui(self, ui):
224 newpatterns = set(pattern for pattern, key, m in self.patterns)
225 for section in (b'decode', b'encode'):
226 for oldpattern, _filter in ui.configitems(section):
227 if oldpattern not in newpatterns:
228 if ui.configsource(section, oldpattern) == b'eol':
229 ui.setconfig(section, oldpattern, b'!', b'eol')
224 230 for pattern, key, m in self.patterns:
225 231 try:
226 232 ui.setconfig(b'decode', pattern, self._decode[key], b'eol')
227 233 ui.setconfig(b'encode', pattern, self._encode[key], b'eol')
228 234 except KeyError:
229 235 ui.warn(
230 236 _(b"ignoring unknown EOL style '%s' from %s\n")
231 237 % (key, self.cfg.source(b'patterns', pattern))
232 238 )
233 239 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
234 240 for k, v in self.cfg.items(b'eol'):
235 241 ui.setconfig(b'eol', k, v, b'eol')
236 242
237 243 def checkrev(self, repo, ctx, files):
238 244 failed = []
239 245 for f in files or ctx.files():
240 246 if f not in ctx:
241 247 continue
242 248 for pattern, key, m in self.patterns:
243 249 if not m(f):
244 250 continue
245 251 target = self._encode[key]
246 252 data = ctx[f].data()
247 253 if (
248 254 target == b"to-lf"
249 255 and b"\r\n" in data
250 256 or target == b"to-crlf"
251 257 and singlelf.search(data)
252 258 ):
253 259 failed.append((f, target, bytes(ctx)))
254 260 break
255 261 return failed
256 262
257 263
258 264 def parseeol(ui, repo, nodes):
259 265 try:
260 266 for node in nodes:
261 267 try:
262 268 if node is None:
263 269 # Cannot use workingctx.data() since it would load
264 270 # and cache the filters before we configure them.
265 271 data = repo.wvfs(b'.hgeol').read()
266 272 else:
267 273 data = repo[node][b'.hgeol'].data()
268 274 return eolfile(ui, repo.root, data)
269 275 except (IOError, LookupError):
270 276 pass
271 277 except errormod.ParseError as inst:
272 278 ui.warn(
273 279 _(
274 280 b"warning: ignoring .hgeol file due to parse error "
275 281 b"at %s: %s\n"
276 282 )
277 283 % (inst.args[1], inst.args[0])
278 284 )
279 285 return None
280 286
281 287
282 288 def ensureenabled(ui):
283 289 """make sure the extension is enabled when used as hook
284 290
285 291 When eol is used through hooks, the extension is never formally loaded and
286 292 enabled. This has some side effect, for example the config declaration is
287 293 never loaded. This function ensure the extension is enabled when running
288 294 hooks.
289 295 """
290 296 if b'eol' in ui._knownconfig:
291 297 return
292 298 ui.setconfig(b'extensions', b'eol', b'', source=b'internal')
293 299 extensions.loadall(ui, [b'eol'])
294 300
295 301
296 302 def _checkhook(ui, repo, node, headsonly):
297 303 # Get revisions to check and touched files at the same time
298 304 ensureenabled(ui)
299 305 files = set()
300 306 revs = set()
301 307 for rev in pycompat.xrange(repo[node].rev(), len(repo)):
302 308 revs.add(rev)
303 309 if headsonly:
304 310 ctx = repo[rev]
305 311 files.update(ctx.files())
306 312 for pctx in ctx.parents():
307 313 revs.discard(pctx.rev())
308 314 failed = []
309 315 for rev in revs:
310 316 ctx = repo[rev]
311 317 eol = parseeol(ui, repo, [ctx.node()])
312 318 if eol:
313 319 failed.extend(eol.checkrev(repo, ctx, files))
314 320
315 321 if failed:
316 322 eols = {b'to-lf': b'CRLF', b'to-crlf': b'LF'}
317 323 msgs = []
318 324 for f, target, node in sorted(failed):
319 325 msgs.append(
320 326 _(b" %s in %s should not have %s line endings")
321 327 % (f, node, eols[target])
322 328 )
323 329 raise errormod.Abort(
324 330 _(b"end-of-line check failed:\n") + b"\n".join(msgs)
325 331 )
326 332
327 333
328 334 def checkallhook(ui, repo, node, hooktype, **kwargs):
329 335 """verify that files have expected EOLs"""
330 336 _checkhook(ui, repo, node, False)
331 337
332 338
333 339 def checkheadshook(ui, repo, node, hooktype, **kwargs):
334 340 """verify that files have expected EOLs"""
335 341 _checkhook(ui, repo, node, True)
336 342
337 343
338 344 # "checkheadshook" used to be called "hook"
339 345 hook = checkheadshook
340 346
341 347
342 348 def preupdate(ui, repo, hooktype, parent1, parent2):
343 349 p1node = scmutil.resolvehexnodeidprefix(repo, parent1)
344 350 repo.loadeol([p1node])
345 351 return False
346 352
347 353
348 354 def uisetup(ui):
349 355 ui.setconfig(b'hooks', b'preupdate.eol', preupdate, b'eol')
350 356
351 357
352 358 def extsetup(ui):
353 359 try:
354 360 extensions.find(b'win32text')
355 361 ui.warn(
356 362 _(
357 363 b"the eol extension is incompatible with the "
358 364 b"win32text extension\n"
359 365 )
360 366 )
361 367 except KeyError:
362 368 pass
363 369
364 370
365 371 def reposetup(ui, repo):
366 372 uisetup(repo.ui)
367 373
368 374 if not repo.local():
369 375 return
370 376 for name, fn in pycompat.iteritems(filters):
371 377 repo.adddatafilter(name, fn)
372 378
373 379 ui.setconfig(b'patch', b'eol', b'auto', b'eol')
374 380
375 381 class eolrepo(repo.__class__):
376 382 def loadeol(self, nodes):
377 383 eol = parseeol(self.ui, self, nodes)
378 384 if eol is None:
379 385 return None
380 386 eol.copytoui(self.ui)
381 387 return eol.match
382 388
383 389 def _hgcleardirstate(self):
384 390 self._eolmatch = self.loadeol([None, b'tip'])
385 391 if not self._eolmatch:
386 392 self._eolmatch = util.never
387 393 return
388 394
389 395 oldeol = None
390 396 try:
391 397 cachemtime = os.path.getmtime(self.vfs.join(b"eol.cache"))
392 398 except OSError:
393 399 cachemtime = 0
394 400 else:
395 401 olddata = self.vfs.read(b"eol.cache")
396 402 if olddata:
397 403 oldeol = eolfile(self.ui, self.root, olddata)
398 404
399 405 try:
400 406 eolmtime = os.path.getmtime(self.wjoin(b".hgeol"))
401 407 except OSError:
402 408 eolmtime = 0
403 409
404 410 if eolmtime >= cachemtime and eolmtime > 0:
405 411 self.ui.debug(b"eol: detected change in .hgeol\n")
406 412
407 413 hgeoldata = self.wvfs.read(b'.hgeol')
408 414 neweol = eolfile(self.ui, self.root, hgeoldata)
409 415
410 416 wlock = None
411 417 try:
412 418 wlock = self.wlock()
413 419 for f in self.dirstate:
414 420 if self.dirstate[f] != b'n':
415 421 continue
416 422 if oldeol is not None:
417 423 if not oldeol.match(f) and not neweol.match(f):
418 424 continue
419 425 oldkey = None
420 426 for pattern, key, m in oldeol.patterns:
421 427 if m(f):
422 428 oldkey = key
423 429 break
424 430 newkey = None
425 431 for pattern, key, m in neweol.patterns:
426 432 if m(f):
427 433 newkey = key
428 434 break
429 435 if oldkey == newkey:
430 436 continue
431 437 # all normal files need to be looked at again since
432 438 # the new .hgeol file specify a different filter
433 439 self.dirstate.normallookup(f)
434 440 # Write the cache to update mtime and cache .hgeol
435 441 with self.vfs(b"eol.cache", b"w") as f:
436 442 f.write(hgeoldata)
437 443 except errormod.LockUnavailable:
438 444 # If we cannot lock the repository and clear the
439 445 # dirstate, then a commit might not see all files
440 446 # as modified. But if we cannot lock the
441 447 # repository, then we can also not make a commit,
442 448 # so ignore the error.
443 449 pass
444 450 finally:
445 451 if wlock is not None:
446 452 wlock.release()
447 453
448 454 def commitctx(self, ctx, error=False, origctx=None):
449 455 for f in sorted(ctx.added() + ctx.modified()):
450 456 if not self._eolmatch(f):
451 457 continue
452 458 fctx = ctx[f]
453 459 if fctx is None:
454 460 continue
455 461 data = fctx.data()
456 462 if stringutil.binary(data):
457 463 # We should not abort here, since the user should
458 464 # be able to say "** = native" to automatically
459 465 # have all non-binary files taken care of.
460 466 continue
461 467 if inconsistenteol(data):
462 468 raise errormod.Abort(
463 469 _(b"inconsistent newline style in %s\n") % f
464 470 )
465 471 return super(eolrepo, self).commitctx(ctx, error, origctx)
466 472
467 473 repo.__class__ = eolrepo
468 474 repo._hgcleardirstate()
@@ -1,312 +1,276
1 1 Test EOL update
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [diff]
5 5 > git = 1
6 6 > EOF
7 7
8 8 $ seteol () {
9 9 > if [ $1 = "LF" ]; then
10 10 > EOL='\n'
11 11 > else
12 12 > EOL='\r\n'
13 13 > fi
14 14 > }
15 15
16 16 $ makerepo () {
17 17 > echo
18 18 > echo "# ==== setup repository ===="
19 19 > echo '% hg init'
20 20 > hg init repo
21 21 > cd repo
22 22 >
23 23 > cat > .hgeol <<EOF
24 24 > [patterns]
25 25 > **.txt = LF
26 26 > EOF
27 27 >
28 28 > printf "first\nsecond\nthird\n" > a.txt
29 29 > printf "f\r\n" > f
30 30 > hg commit --addremove -m 'LF commit'
31 31 >
32 32 > cat > .hgeol <<EOF
33 33 > [patterns]
34 34 > **.txt = CRLF
35 35 > f = LF
36 36 > EOF
37 37 >
38 38 > printf "first\r\nsecond\r\nthird\r\n" > a.txt
39 39 > printf "f\n" > f
40 40 > hg commit -m 'CRLF commit'
41 41 >
42 42 > cd ..
43 43 > }
44 44
45 45 $ dotest () {
46 46 > seteol $1
47 47 >
48 48 > echo
49 49 > echo "% hg clone repo repo-$1"
50 50 > hg clone --noupdate repo repo-$1
51 51 > cd repo-$1
52 52 >
53 53 > cat > .hg/hgrc <<EOF
54 54 > [extensions]
55 55 > eol =
56 56 > EOF
57 57 >
58 58 > hg update
59 59 >
60 60 > echo '% a.txt (before)'
61 61 > cat a.txt
62 62 >
63 63 > printf "first${EOL}third${EOL}" > a.txt
64 64 >
65 65 > echo '% a.txt (after)'
66 66 > cat a.txt
67 67 > echo '% hg diff'
68 68 > hg diff
69 69 >
70 70 > echo '% hg update 0'
71 71 > hg update 0
72 72 >
73 73 > echo '% a.txt'
74 74 > cat a.txt
75 75 > echo '% hg diff'
76 76 > hg diff
77 77 >
78 78 >
79 79 > cd ..
80 80 > rm -r repo-$1
81 81 > }
82 82
83 83 $ makerepo
84 84
85 85 # ==== setup repository ====
86 86 % hg init
87 87 adding .hgeol
88 88 adding a.txt
89 89 adding f
90 90 $ dotest LF
91 91
92 92 % hg clone repo repo-LF
93 93 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 94 % a.txt (before)
95 95 first\r (esc)
96 96 second\r (esc)
97 97 third\r (esc)
98 98 % a.txt (after)
99 99 first
100 100 third
101 101 % hg diff
102 102 diff --git a/a.txt b/a.txt
103 103 --- a/a.txt
104 104 +++ b/a.txt
105 105 @@ -1,3 +1,2 @@
106 106 first\r (esc)
107 107 -second\r (esc)
108 108 third\r (esc)
109 109 % hg update 0
110 110 merging a.txt
111 111 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
112 112 % a.txt
113 113 first
114 114 third
115 115 % hg diff
116 116 diff --git a/a.txt b/a.txt
117 117 --- a/a.txt
118 118 +++ b/a.txt
119 119 @@ -1,3 +1,2 @@
120 120 first
121 121 -second
122 122 third
123 diff --git a/f b/f
124 --- a/f
125 +++ b/f
126 @@ -1,1 +1,1 @@
127 -f\r (esc)
128 +f
129 123 $ dotest CRLF
130 124
131 125 % hg clone repo repo-CRLF
132 126 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 127 % a.txt (before)
134 128 first\r (esc)
135 129 second\r (esc)
136 130 third\r (esc)
137 131 % a.txt (after)
138 132 first\r (esc)
139 133 third\r (esc)
140 134 % hg diff
141 135 diff --git a/a.txt b/a.txt
142 136 --- a/a.txt
143 137 +++ b/a.txt
144 138 @@ -1,3 +1,2 @@
145 139 first\r (esc)
146 140 -second\r (esc)
147 141 third\r (esc)
148 142 % hg update 0
149 143 merging a.txt
150 144 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
151 145 % a.txt
152 146 first
153 147 third
154 148 % hg diff
155 149 diff --git a/a.txt b/a.txt
156 150 --- a/a.txt
157 151 +++ b/a.txt
158 152 @@ -1,3 +1,2 @@
159 153 first
160 154 -second
161 155 third
162 diff --git a/f b/f
163 --- a/f
164 +++ b/f
165 @@ -1,1 +1,1 @@
166 -f\r (esc)
167 +f
168 156
169 157 Test in repo using eol extension, while keeping an eye on how filters are
170 158 applied:
171 159
172 160 $ cd repo
173 161
174 162 $ hg up -q -c -r null
175 163 $ cat > .hg/hgrc <<EOF
176 164 > [extensions]
177 165 > eol =
178 166 > EOF
179 167
180 Update to revision 0 which has no .hgeol . Unfortunately, it uses the filter
181 from tip ... which evidently is wrong:
168 Update to revision 0 which has no .hgeol, shouldn't use any filters, and
169 obviously should leave things as tidy as they were before the clean update.
182 170
183 171 $ hg up -c -r 0 -v --debug
184 172 resolving manifests
185 173 branchmerge: False, force: False, partial: False
186 174 ancestor: 000000000000, local: 000000000000+, remote: 15cbdf8ca3db
187 175 calling hook preupdate.eol: hgext.eol.preupdate
188 176 .hgeol: remote created -> g
189 177 getting .hgeol
190 178 filtering .hgeol through isbinary
191 179 a.txt: remote created -> g
192 180 getting a.txt
193 181 filtering a.txt through tolf
194 182 f: remote created -> g
195 183 getting f
196 filtering f through tolf
197 184 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 185 $ hg st
199 M f
200 $ touch .hgeol * # ensure consistent dirtyness checks ignoring dirstate
201 $ hg up -C -r 0 -v --debug
202 eol: detected change in .hgeol
203 filtering .hgeol through isbinary
204 filtering a.txt through tolf
205 resolving manifests
206 branchmerge: False, force: True, partial: False
207 ancestor: 15cbdf8ca3db+, local: 15cbdf8ca3db+, remote: 15cbdf8ca3db
208 calling hook preupdate.eol: hgext.eol.preupdate
209 f: remote is newer -> g
210 getting f
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 186
213 187 $ hg branch b
214 188 marked working directory as branch b
215 189 (branches are permanent and global, did you want a bookmark?)
216 190 $ hg ci -m b
217 191
218 192 Merge changes that apply a filter to f:
219 193
220 194 $ hg merge 1
221 195 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 196 (branch merge, don't forget to commit)
223 197 $ hg st
224 198 M .hgeol
225 199 M a.txt
226 200 M f
227 201 $ hg diff
228 202 diff --git a/.hgeol b/.hgeol
229 203 --- a/.hgeol
230 204 +++ b/.hgeol
231 205 @@ -1,2 +1,3 @@
232 206 [patterns]
233 207 -**.txt = LF
234 208 +**.txt = CRLF
235 209 +f = LF
236 210 diff --git a/a.txt b/a.txt
237 211 --- a/a.txt
238 212 +++ b/a.txt
239 213 @@ -1,3 +1,3 @@
240 214 -first
241 215 -second
242 216 -third
243 217 +first\r (esc)
244 218 +second\r (esc)
245 219 +third\r (esc)
246 220 diff --git a/f b/f
247 221 --- a/f
248 222 +++ b/f
249 223 @@ -1,1 +1,1 @@
250 224 -f\r (esc)
251 225 +f
252 226
253 Abort the merge with up -C to revision 0 ... but notice how .hgeol changes are
254 not detected correctly: f is filtered with tolf even though there is no filter
255 for f in revision 0, and it thus ends up with working directory changes.
227 Abort the merge with up -C to revision 0.
228 Note that files are filtered correctly for revision 0: f is not filtered, a.txt
229 is filtered with tolf, and everything is left tidy.
256 230
257 231 $ touch .hgeol * # ensure consistent dirtyness checks ignoring dirstate
258 232 $ hg up -C -r 0 -v --debug
259 233 eol: detected change in .hgeol
260 234 resolving manifests
261 235 branchmerge: False, force: True, partial: False
262 236 ancestor: 1db78bdd3bd6+, local: 1db78bdd3bd6+, remote: 15cbdf8ca3db
263 237 calling hook preupdate.eol: hgext.eol.preupdate
264 238 .hgeol: remote is newer -> g
265 239 getting .hgeol
266 240 filtering .hgeol through isbinary
267 241 a.txt: remote is newer -> g
268 242 getting a.txt
269 243 filtering a.txt through tolf
270 244 f: remote is newer -> g
271 245 getting f
272 filtering f through tolf
273 246 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 247
275 248 $ touch .hgeol *
276 249 $ hg st --debug
277 250 eol: detected change in .hgeol
278 251 filtering .hgeol through isbinary
279 252 filtering a.txt through tolf
280 M f
281 253 $ hg diff
282 diff --git a/f b/f
283 --- a/f
284 +++ b/f
285 @@ -1,1 +1,1 @@
286 -f\r (esc)
287 +f
288 254
289 Workaround: Update again - this will read the right .hgeol:
255 Things were clean, and updating again will not change anything:
290 256
291 257 $ touch .hgeol *
292 258 $ hg up -C -r 0 -v --debug
293 259 eol: detected change in .hgeol
294 260 filtering .hgeol through isbinary
295 261 filtering a.txt through tolf
296 262 resolving manifests
297 263 branchmerge: False, force: True, partial: False
298 264 ancestor: 15cbdf8ca3db+, local: 15cbdf8ca3db+, remote: 15cbdf8ca3db
299 265 calling hook preupdate.eol: hgext.eol.preupdate
300 f: remote is newer -> g
301 getting f
302 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
303 267
304 268 $ touch .hgeol *
305 269 $ hg st --debug
306 270 eol: detected change in .hgeol
307 271 filtering .hgeol through isbinary
308 272 filtering a.txt through tolf
309 273
310 274 $ cd ..
311 275
312 276 $ rm -r repo
General Comments 0
You need to be logged in to leave comments. Login now