##// END OF EJS Templates
eol: stop after first matched rule in hook (issue2660)...
Antoine Pitrou -
r13501:50b825c1 stable
parent child Browse files
Show More
@@ -1,283 +1,285 b''
1 """automatically manage newlines in repository files
1 """automatically manage newlines in repository files
2
2
3 This extension allows you to manage the type of line endings (CRLF or
3 This extension allows you to manage the type of line endings (CRLF or
4 LF) that are used in the repository and in the local working
4 LF) that are used in the repository and in the local working
5 directory. That way you can get CRLF line endings on Windows and LF on
5 directory. That way you can get CRLF line endings on Windows and LF on
6 Unix/Mac, thereby letting everybody use their OS native line endings.
6 Unix/Mac, thereby letting everybody use their OS native line endings.
7
7
8 The extension reads its configuration from a versioned ``.hgeol``
8 The extension reads its configuration from a versioned ``.hgeol``
9 configuration file found in the root of the working copy. The
9 configuration file found in the root of the working copy. The
10 ``.hgeol`` file use the same syntax as all other Mercurial
10 ``.hgeol`` file use the same syntax as all other Mercurial
11 configuration files. It uses two sections, ``[patterns]`` and
11 configuration files. It uses two sections, ``[patterns]`` and
12 ``[repository]``.
12 ``[repository]``.
13
13
14 The ``[patterns]`` section specifies how line endings should be
14 The ``[patterns]`` section specifies how line endings should be
15 converted between the working copy and the repository. The format is
15 converted between the working copy and the repository. The format is
16 specified by a file pattern. The first match is used, so put more
16 specified by a file pattern. The first match is used, so put more
17 specific patterns first. The available line endings are ``LF``,
17 specific patterns first. The available line endings are ``LF``,
18 ``CRLF``, and ``BIN``.
18 ``CRLF``, and ``BIN``.
19
19
20 Files with the declared format of ``CRLF`` or ``LF`` are always
20 Files with the declared format of ``CRLF`` or ``LF`` are always
21 checked out and stored in the repository in that format and files
21 checked out and stored in the repository in that format and files
22 declared to be binary (``BIN``) are left unchanged. Additionally,
22 declared to be binary (``BIN``) are left unchanged. Additionally,
23 ``native`` is an alias for checking out in the platform's default line
23 ``native`` is an alias for checking out in the platform's default line
24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
26 default behaviour; it is only needed if you need to override a later,
26 default behaviour; it is only needed if you need to override a later,
27 more general pattern.
27 more general pattern.
28
28
29 The optional ``[repository]`` section specifies the line endings to
29 The optional ``[repository]`` section specifies the line endings to
30 use for files stored in the repository. It has a single setting,
30 use for files stored in the repository. It has a single setting,
31 ``native``, which determines the storage line endings for files
31 ``native``, which determines the storage line endings for files
32 declared as ``native`` in the ``[patterns]`` section. It can be set to
32 declared as ``native`` in the ``[patterns]`` section. It can be set to
33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
34 that on Windows, files configured as ``native`` (``CRLF`` by default)
34 that on Windows, files configured as ``native`` (``CRLF`` by default)
35 will be converted to ``LF`` when stored in the repository. Files
35 will be converted to ``LF`` when stored in the repository. Files
36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
37 are always stored as-is in the repository.
37 are always stored as-is in the repository.
38
38
39 Example versioned ``.hgeol`` file::
39 Example versioned ``.hgeol`` file::
40
40
41 [patterns]
41 [patterns]
42 **.py = native
42 **.py = native
43 **.vcproj = CRLF
43 **.vcproj = CRLF
44 **.txt = native
44 **.txt = native
45 Makefile = LF
45 Makefile = LF
46 **.jpg = BIN
46 **.jpg = BIN
47
47
48 [repository]
48 [repository]
49 native = LF
49 native = LF
50
50
51 .. note::
51 .. note::
52 The rules will first apply when files are touched in the working
52 The rules will first apply when files are touched in the working
53 copy, e.g. by updating to null and back to tip to touch all files.
53 copy, e.g. by updating to null and back to tip to touch all files.
54
54
55 The extension uses an optional ``[eol]`` section in your hgrc file
55 The extension uses an optional ``[eol]`` section in your hgrc file
56 (not the ``.hgeol`` file) for settings that control the overall
56 (not the ``.hgeol`` file) for settings that control the overall
57 behavior. There are two settings:
57 behavior. There are two settings:
58
58
59 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
59 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
60 ``CRLF`` to override the default interpretation of ``native`` for
60 ``CRLF`` to override the default interpretation of ``native`` for
61 checkout. This can be used with :hg:`archive` on Unix, say, to
61 checkout. This can be used with :hg:`archive` on Unix, say, to
62 generate an archive where files have line endings for Windows.
62 generate an archive where files have line endings for Windows.
63
63
64 - ``eol.only-consistent`` (default True) can be set to False to make
64 - ``eol.only-consistent`` (default True) can be set to False to make
65 the extension convert files with inconsistent EOLs. Inconsistent
65 the extension convert files with inconsistent EOLs. Inconsistent
66 means that there is both ``CRLF`` and ``LF`` present in the file.
66 means that there is both ``CRLF`` and ``LF`` present in the file.
67 Such files are normally not touched under the assumption that they
67 Such files are normally not touched under the assumption that they
68 have mixed EOLs on purpose.
68 have mixed EOLs on purpose.
69
69
70 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
70 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
71 like the deprecated win32text extension does. This means that you can
71 like the deprecated win32text extension does. This means that you can
72 disable win32text and enable eol and your filters will still work. You
72 disable win32text and enable eol and your filters will still work. You
73 only need to these filters until you have prepared a ``.hgeol`` file.
73 only need to these filters until you have prepared a ``.hgeol`` file.
74
74
75 The ``win32text.forbid*`` hooks provided by the win32text extension
75 The ``win32text.forbid*`` hooks provided by the win32text extension
76 have been unified into a single hook named ``eol.hook``. The hook will
76 have been unified into a single hook named ``eol.hook``. The hook will
77 lookup the expected line endings from the ``.hgeol`` file, which means
77 lookup the expected line endings from the ``.hgeol`` file, which means
78 you must migrate to a ``.hgeol`` file first before using the hook.
78 you must migrate to a ``.hgeol`` file first before using the hook.
79
79
80 See :hg:`help patterns` for more information about the glob patterns
80 See :hg:`help patterns` for more information about the glob patterns
81 used.
81 used.
82 """
82 """
83
83
84 from mercurial.i18n import _
84 from mercurial.i18n import _
85 from mercurial import util, config, extensions, match, error
85 from mercurial import util, config, extensions, match, error
86 import re, os
86 import re, os
87
87
88 # Matches a lone LF, i.e., one that is not part of CRLF.
88 # Matches a lone LF, i.e., one that is not part of CRLF.
89 singlelf = re.compile('(^|[^\r])\n')
89 singlelf = re.compile('(^|[^\r])\n')
90 # Matches a single EOL which can either be a CRLF where repeated CR
90 # Matches a single EOL which can either be a CRLF where repeated CR
91 # are removed or a LF. We do not care about old Machintosh files, so a
91 # are removed or a LF. We do not care about old Machintosh files, so a
92 # stray CR is an error.
92 # stray CR is an error.
93 eolre = re.compile('\r*\n')
93 eolre = re.compile('\r*\n')
94
94
95
95
96 def inconsistenteol(data):
96 def inconsistenteol(data):
97 return '\r\n' in data and singlelf.search(data)
97 return '\r\n' in data and singlelf.search(data)
98
98
99 def tolf(s, params, ui, **kwargs):
99 def tolf(s, params, ui, **kwargs):
100 """Filter to convert to LF EOLs."""
100 """Filter to convert to LF EOLs."""
101 if util.binary(s):
101 if util.binary(s):
102 return s
102 return s
103 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
103 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
104 return s
104 return s
105 return eolre.sub('\n', s)
105 return eolre.sub('\n', s)
106
106
107 def tocrlf(s, params, ui, **kwargs):
107 def tocrlf(s, params, ui, **kwargs):
108 """Filter to convert to CRLF EOLs."""
108 """Filter to convert to CRLF EOLs."""
109 if util.binary(s):
109 if util.binary(s):
110 return s
110 return s
111 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
111 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
112 return s
112 return s
113 return eolre.sub('\r\n', s)
113 return eolre.sub('\r\n', s)
114
114
115 def isbinary(s, params):
115 def isbinary(s, params):
116 """Filter to do nothing with the file."""
116 """Filter to do nothing with the file."""
117 return s
117 return s
118
118
119 filters = {
119 filters = {
120 'to-lf': tolf,
120 'to-lf': tolf,
121 'to-crlf': tocrlf,
121 'to-crlf': tocrlf,
122 'is-binary': isbinary,
122 'is-binary': isbinary,
123 # The following provide backwards compatibility with win32text
123 # The following provide backwards compatibility with win32text
124 'cleverencode:': tolf,
124 'cleverencode:': tolf,
125 'cleverdecode:': tocrlf
125 'cleverdecode:': tocrlf
126 }
126 }
127
127
128
128
129 def hook(ui, repo, node, hooktype, **kwargs):
129 def hook(ui, repo, node, hooktype, **kwargs):
130 """verify that files have expected EOLs"""
130 """verify that files have expected EOLs"""
131 files = set()
131 files = set()
132 for rev in xrange(repo[node].rev(), len(repo)):
132 for rev in xrange(repo[node].rev(), len(repo)):
133 files.update(repo[rev].files())
133 files.update(repo[rev].files())
134 tip = repo['tip']
134 tip = repo['tip']
135 for f in files:
135 for f in files:
136 if f not in tip:
136 if f not in tip:
137 continue
137 continue
138 for pattern, target in ui.configitems('encode'):
138 for pattern, target in ui.configitems('encode'):
139 if match.match(repo.root, '', [pattern])(f):
139 if match.match(repo.root, '', [pattern])(f):
140 data = tip[f].data()
140 data = tip[f].data()
141 if target == "to-lf" and "\r\n" in data:
141 if target == "to-lf" and "\r\n" in data:
142 raise util.Abort(_("%s should not have CRLF line endings")
142 raise util.Abort(_("%s should not have CRLF line endings")
143 % f)
143 % f)
144 elif target == "to-crlf" and singlelf.search(data):
144 elif target == "to-crlf" and singlelf.search(data):
145 raise util.Abort(_("%s should not have LF line endings")
145 raise util.Abort(_("%s should not have LF line endings")
146 % f)
146 % f)
147 # Ignore other rules for this file
148 break
147
149
148
150
149 def preupdate(ui, repo, hooktype, parent1, parent2):
151 def preupdate(ui, repo, hooktype, parent1, parent2):
150 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
152 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
151 repo.readhgeol(parent1)
153 repo.readhgeol(parent1)
152 return False
154 return False
153
155
154 def uisetup(ui):
156 def uisetup(ui):
155 ui.setconfig('hooks', 'preupdate.eol', preupdate)
157 ui.setconfig('hooks', 'preupdate.eol', preupdate)
156
158
157 def extsetup(ui):
159 def extsetup(ui):
158 try:
160 try:
159 extensions.find('win32text')
161 extensions.find('win32text')
160 raise util.Abort(_("the eol extension is incompatible with the "
162 raise util.Abort(_("the eol extension is incompatible with the "
161 "win32text extension"))
163 "win32text extension"))
162 except KeyError:
164 except KeyError:
163 pass
165 pass
164
166
165
167
166 def reposetup(ui, repo):
168 def reposetup(ui, repo):
167 uisetup(repo.ui)
169 uisetup(repo.ui)
168 #print "reposetup for", repo.root
170 #print "reposetup for", repo.root
169
171
170 if not repo.local():
172 if not repo.local():
171 return
173 return
172 for name, fn in filters.iteritems():
174 for name, fn in filters.iteritems():
173 repo.adddatafilter(name, fn)
175 repo.adddatafilter(name, fn)
174
176
175 ui.setconfig('patch', 'eol', 'auto')
177 ui.setconfig('patch', 'eol', 'auto')
176
178
177 class eolrepo(repo.__class__):
179 class eolrepo(repo.__class__):
178
180
179 _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
181 _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
180 _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
182 _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
181
183
182 def readhgeol(self, node=None, data=None):
184 def readhgeol(self, node=None, data=None):
183 if data is None:
185 if data is None:
184 try:
186 try:
185 if node is None:
187 if node is None:
186 data = self.wfile('.hgeol').read()
188 data = self.wfile('.hgeol').read()
187 else:
189 else:
188 data = self[node]['.hgeol'].data()
190 data = self[node]['.hgeol'].data()
189 except (IOError, LookupError):
191 except (IOError, LookupError):
190 return None
192 return None
191
193
192 if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
194 if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
193 self._decode['NATIVE'] = 'to-lf'
195 self._decode['NATIVE'] = 'to-lf'
194 else:
196 else:
195 self._decode['NATIVE'] = 'to-crlf'
197 self._decode['NATIVE'] = 'to-crlf'
196
198
197 eol = config.config()
199 eol = config.config()
198 # Our files should not be touched. The pattern must be
200 # Our files should not be touched. The pattern must be
199 # inserted first override a '** = native' pattern.
201 # inserted first override a '** = native' pattern.
200 eol.set('patterns', '.hg*', 'BIN')
202 eol.set('patterns', '.hg*', 'BIN')
201 # We can then parse the user's patterns.
203 # We can then parse the user's patterns.
202 eol.parse('.hgeol', data)
204 eol.parse('.hgeol', data)
203
205
204 if eol.get('repository', 'native') == 'CRLF':
206 if eol.get('repository', 'native') == 'CRLF':
205 self._encode['NATIVE'] = 'to-crlf'
207 self._encode['NATIVE'] = 'to-crlf'
206 else:
208 else:
207 self._encode['NATIVE'] = 'to-lf'
209 self._encode['NATIVE'] = 'to-lf'
208
210
209 for pattern, style in eol.items('patterns'):
211 for pattern, style in eol.items('patterns'):
210 key = style.upper()
212 key = style.upper()
211 try:
213 try:
212 self.ui.setconfig('decode', pattern, self._decode[key])
214 self.ui.setconfig('decode', pattern, self._decode[key])
213 self.ui.setconfig('encode', pattern, self._encode[key])
215 self.ui.setconfig('encode', pattern, self._encode[key])
214 except KeyError:
216 except KeyError:
215 self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
217 self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
216 % (style, eol.source('patterns', pattern)))
218 % (style, eol.source('patterns', pattern)))
217
219
218 include = []
220 include = []
219 exclude = []
221 exclude = []
220 for pattern, style in eol.items('patterns'):
222 for pattern, style in eol.items('patterns'):
221 key = style.upper()
223 key = style.upper()
222 if key == 'BIN':
224 if key == 'BIN':
223 exclude.append(pattern)
225 exclude.append(pattern)
224 else:
226 else:
225 include.append(pattern)
227 include.append(pattern)
226
228
227 # This will match the files for which we need to care
229 # This will match the files for which we need to care
228 # about inconsistent newlines.
230 # about inconsistent newlines.
229 return match.match(self.root, '', [], include, exclude)
231 return match.match(self.root, '', [], include, exclude)
230
232
231 def _hgcleardirstate(self):
233 def _hgcleardirstate(self):
232 self._eolfile = self.readhgeol() or self.readhgeol('tip')
234 self._eolfile = self.readhgeol() or self.readhgeol('tip')
233
235
234 if not self._eolfile:
236 if not self._eolfile:
235 self._eolfile = util.never
237 self._eolfile = util.never
236 return
238 return
237
239
238 try:
240 try:
239 cachemtime = os.path.getmtime(self.join("eol.cache"))
241 cachemtime = os.path.getmtime(self.join("eol.cache"))
240 except OSError:
242 except OSError:
241 cachemtime = 0
243 cachemtime = 0
242
244
243 try:
245 try:
244 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
246 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
245 except OSError:
247 except OSError:
246 eolmtime = 0
248 eolmtime = 0
247
249
248 if eolmtime > cachemtime:
250 if eolmtime > cachemtime:
249 ui.debug("eol: detected change in .hgeol\n")
251 ui.debug("eol: detected change in .hgeol\n")
250 # TODO: we could introduce a method for this in dirstate.
252 # TODO: we could introduce a method for this in dirstate.
251 wlock = None
253 wlock = None
252 try:
254 try:
253 wlock = self.wlock()
255 wlock = self.wlock()
254 for f, e in self.dirstate._map.iteritems():
256 for f, e in self.dirstate._map.iteritems():
255 self.dirstate._map[f] = (e[0], e[1], -1, 0)
257 self.dirstate._map[f] = (e[0], e[1], -1, 0)
256 self.dirstate._dirty = True
258 self.dirstate._dirty = True
257 # Touch the cache to update mtime.
259 # Touch the cache to update mtime.
258 self.opener("eol.cache", "w").close()
260 self.opener("eol.cache", "w").close()
259 wlock.release()
261 wlock.release()
260 except error.LockUnavailable:
262 except error.LockUnavailable:
261 # If we cannot lock the repository and clear the
263 # If we cannot lock the repository and clear the
262 # dirstate, then a commit might not see all files
264 # dirstate, then a commit might not see all files
263 # as modified. But if we cannot lock the
265 # as modified. But if we cannot lock the
264 # repository, then we can also not make a commit,
266 # repository, then we can also not make a commit,
265 # so ignore the error.
267 # so ignore the error.
266 pass
268 pass
267
269
268 def commitctx(self, ctx, error=False):
270 def commitctx(self, ctx, error=False):
269 for f in sorted(ctx.added() + ctx.modified()):
271 for f in sorted(ctx.added() + ctx.modified()):
270 if not self._eolfile(f):
272 if not self._eolfile(f):
271 continue
273 continue
272 data = ctx[f].data()
274 data = ctx[f].data()
273 if util.binary(data):
275 if util.binary(data):
274 # We should not abort here, since the user should
276 # We should not abort here, since the user should
275 # be able to say "** = native" to automatically
277 # be able to say "** = native" to automatically
276 # have all non-binary files taken care of.
278 # have all non-binary files taken care of.
277 continue
279 continue
278 if inconsistenteol(data):
280 if inconsistenteol(data):
279 raise util.Abort(_("inconsistent newline style "
281 raise util.Abort(_("inconsistent newline style "
280 "in %s\n" % f))
282 "in %s\n" % f))
281 return super(eolrepo, self).commitctx(ctx, error)
283 return super(eolrepo, self).commitctx(ctx, error)
282 repo.__class__ = eolrepo
284 repo.__class__ = eolrepo
283 repo._hgcleardirstate()
285 repo._hgcleardirstate()
@@ -1,63 +1,90 b''
1 Test the EOL hook
1 Test the EOL hook
2
2
3 $ cat > $HGRCPATH <<EOF
3 $ cat > $HGRCPATH <<EOF
4 > [diff]
4 > [diff]
5 > git = True
5 > git = True
6 > EOF
6 > EOF
7 $ hg init main
7 $ hg init main
8 $ cat > main/.hg/hgrc <<EOF
8 $ cat > main/.hg/hgrc <<EOF
9 > [extensions]
9 > [extensions]
10 > eol =
10 > eol =
11 >
11 >
12 > [hooks]
12 > [hooks]
13 > pretxnchangegroup = python:hgext.eol.hook
13 > pretxnchangegroup = python:hgext.eol.hook
14 > EOF
14 > EOF
15 $ hg clone main fork
15 $ hg clone main fork
16 updating to branch default
16 updating to branch default
17 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 $ cd fork
18 $ cd fork
19
19
20 Create repo
20 Create repo
21 $ cat > .hgeol <<EOF
21 $ cat > .hgeol <<EOF
22 > [patterns]
22 > [patterns]
23 > mixed.txt = BIN
23 > mixed.txt = BIN
24 > crlf.txt = CRLF
24 > **.txt = native
25 > **.txt = native
25 > EOF
26 > EOF
26 $ hg add .hgeol
27 $ hg add .hgeol
27 $ hg commit -m 'Commit .hgeol'
28 $ hg commit -m 'Commit .hgeol'
28
29
29 $ printf "first\nsecond\nthird\n" > a.txt
30 $ printf "first\nsecond\nthird\n" > a.txt
30 $ hg add a.txt
31 $ hg add a.txt
31 $ hg commit -m 'LF a.txt'
32 $ hg commit -m 'LF a.txt'
32 $ hg push ../main
33 $ hg push ../main
33 pushing to ../main
34 pushing to ../main
34 searching for changes
35 searching for changes
35 adding changesets
36 adding changesets
36 adding manifests
37 adding manifests
37 adding file changes
38 adding file changes
38 added 2 changesets with 2 changes to 2 files
39 added 2 changesets with 2 changes to 2 files
39
40
40 $ printf "first\r\nsecond\r\nthird\n" > a.txt
41 $ printf "first\r\nsecond\r\nthird\n" > a.txt
41 $ hg commit -m 'CRLF a.txt'
42 $ hg commit -m 'CRLF a.txt'
42 $ hg push ../main
43 $ hg push ../main
43 pushing to ../main
44 pushing to ../main
44 searching for changes
45 searching for changes
45 adding changesets
46 adding changesets
46 adding manifests
47 adding manifests
47 adding file changes
48 adding file changes
48 added 1 changesets with 1 changes to 1 files
49 added 1 changesets with 1 changes to 1 files
49 error: pretxnchangegroup hook failed: a.txt should not have CRLF line endings
50 error: pretxnchangegroup hook failed: a.txt should not have CRLF line endings
50 transaction abort!
51 transaction abort!
51 rollback completed
52 rollback completed
52 abort: a.txt should not have CRLF line endings
53 abort: a.txt should not have CRLF line endings
53 [255]
54 [255]
54
55
55 $ printf "first\nsecond\nthird\n" > a.txt
56 $ printf "first\nsecond\nthird\n" > a.txt
56 $ hg commit -m 'LF a.txt (fixed)'
57 $ hg commit -m 'LF a.txt (fixed)'
57 $ hg push ../main
58 $ hg push ../main
58 pushing to ../main
59 pushing to ../main
59 searching for changes
60 searching for changes
60 adding changesets
61 adding changesets
61 adding manifests
62 adding manifests
62 adding file changes
63 adding file changes
63 added 2 changesets with 2 changes to 1 files
64 added 2 changesets with 2 changes to 1 files
65
66 $ printf "first\nsecond\nthird\n" > crlf.txt
67 $ hg add crlf.txt
68 $ hg commit -m 'LF crlf.txt'
69 $ hg push ../main
70 pushing to ../main
71 searching for changes
72 adding changesets
73 adding manifests
74 adding file changes
75 added 1 changesets with 1 changes to 1 files
76 error: pretxnchangegroup hook failed: crlf.txt should not have LF line endings
77 transaction abort!
78 rollback completed
79 abort: crlf.txt should not have LF line endings
80 [255]
81
82 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
83 $ hg commit -m 'CRLF crlf.txt (fixed)'
84 $ hg push ../main
85 pushing to ../main
86 searching for changes
87 adding changesets
88 adding manifests
89 adding file changes
90 added 2 changesets with 2 changes to 1 files
General Comments 0
You need to be logged in to leave comments. Login now