Enforce core.autocrlf=input through .gitattributes
Asked Answered
O

3

15

Is there a way to enforce core.autocrlf=input from within the .gitattributes in order to propagate the policy throughout my colleagues?

In detail what I want is to convert to lf on add and leave as is on checkout.

The problem is that neither text nor eol do what I want in .gitattributes since eol has 3 acceptable values:

  1. lf
  2. crlf
  3. native

Ideally I would like my .gitattributes file to look like this:

* text eol=asis

Okay answered 8/3, 2017 at 9:51 Comment(2)
What line ending do you want in the repository itself? LF? Whatever was originally in the working tree?Tosspot
The setting you are looking for is this: * text=auto eol=lfManila
T
11

It isn't clear exactly what you mean by "as is" in the working tree. If you want Git to store line endings in LF in the repository and let the user decide what they want in the working tree (based on their platform and/or settings), then use this:

* text

That will force line ending conversion on, and Git will convert files to LF in the repository and will honor the user's preferred line endings on checkout. If not all of your files are text (i.e., you have images or other binaries) and you'd like Git to guess, then you can use this:

* text=auto

Note that as mentioned by LoopInFool, this will not cause files that are already CRLF to be converted, so you'll need to be sure that your files are already in LF in the repository, or list those files types explicitly as text (e.g., *.c text).

The behavior of core.autocrlf=input is to force conversion to LF on addition into the repository and not to perform any conversion on checkout; that is, to always use LF endings regardless of the user's settings. If that's the behavior you want, then you can do that with the following:

* eol=lf

Note that setting eol effectively sets the text attribute, so you should not set it on any files that are binary.

If what you want is for Git to match the line endings that are already in the working tree on checkout (e.g, by reading the file), then it won't do that. Git always does line ending conversions based on configuration without regard to what's already there, so the user will have to indicate their preference in some way or accept the platform default behavior.

In addition, Git always counts any modification to the file size as a modification in git status, even if it ignores those changes on add (say, because you've only changed line endings); this is similarly not avoidable.

If what you want is something entirely different, please go into a little more detail about what behavior you want, and I'll update with more details.

Tosspot answered 18/4, 2020 at 3:30 Comment(0)
T
2

The closest thing to core.autocrlf=input is to use text=auto in .gitattributes.

That specifies they are text files, so new files will be put in the repo with LF line endings. And, according to The gitattributes documentation, by setting text=auto:

When the file has been committed with CRLF, no conversion is done.

We converted a Mercurial repo to Git recently. Mercurial does no eol conversions, so many of our files already had CRLF after the conversion. Setting text=auto for those file extensions allows new files to still be normalized to LF, but doesn't touch the existing files, and doesn't show them as modified in the current directory.

Tollefson answered 22/2, 2020 at 18:41 Comment(0)
C
1

In detail what I want is to convert to lf on commit and leave as is on checkout.

Git doesn't convert on commit, but rather on git add. (More precisely, it does conversions on operations that copy the object into the repository and produce a hash value—but for most purposes, that's just git add anyway.) At this time it applies any "clean" filters and does input-side EOL operations. (Likewise, output-side "smudge" filters and EOL operations occur when copying out from the repository to the work-tree, which for most purposes is git checkout and git reset --hard.)

According to the gitattributes documentation, setting eol=lf:

... forces Git to normalize line endings to LF on checkin and prevents conversion to CRLF when the file is checked out.

Hence, though I have not actually tested this, it sounds like * eol=lf is just what you want. Note that this is different from core.eol, which behaves as you described in your question; this is only for a .gitattributes setting, which applies to the files that match the name-pattern.

Chokedamp answered 8/3, 2017 at 11:20 Comment(8)
Well... I proposed to the OP eol=lf before... no joy: #3207343Tivoli
@Chokedamp I corrected commit to add as you said. Regarding the gitattributes documentation (git-scm.com/docs/gitattributes#_effects) I quote "To control what line ending style is used in the working directory, use the eol attribute for a single file and the core.eol configuration variable for all text files." which suggests that core.eol is practicaly the same as eol. Furthermore, and I quote again "...ensure that .vcproj files have CRLF and .sh files have LF in the working directory, ..." which refers to *.sh text eol=lf"Okay
The core.* settings apply only if there is no more-specific setting in .gitattributes. In particular, if there is no .gitattributes eol= entry for a path-name, Git has to (1) decide if the file is text and then (2) apply core.eol or core.autocrlf rules. A * text=auto .gitattributes entry applies Git's guess to all files that have no later-line more-specific rule. Note that if there are multiple .gitattributes files and/or a .git/info/attributes you must apply all the precedence rules as well; and there are rules for which of index and work-tree .gitattributes overrides.Chokedamp
BTW, the documentation on this seems to be gradually improving, but it's still a mess, and some things in the code seem not to match some things in the documentation sometimes. So you may need to mention specific Git versions as well. I suspect the Windows Git folks may occasionally fight with the non-Windows folks over these things too :-)Chokedamp
The documentation is not awfull but it is at least confusing. I am using git 2.8.3 under cygwin and git 1.8.3.1 under CentOS 7 which I've checked and both use eol instead of backwards compatible crlf in .gitattributes. @Chokedamp another thing suggesting your claim found in the documentation is that the backwards compatible of eol=lf is crlf=input. Nevertheless, after a hands on, I found that autocrlf=input would get me a clean clone while a eol=lf would have end-of-line conflicts after cloning.Okay
Also, assuming eol=lf solves the first leg of my question which is to perform no operation at all on line endings on checkout, what about the second part which wants everything to be converted to line feed on add? I think that in spite of not clarifying it, eol=lf implies that the leftmost part is text which in turn implies that should be converted to lf on the remoteOkay
Hm, 1.8.3.1 is old enough that I'd be suspicious of different behavior. Still, it's worth noting that you will see files as "modified" if they have CRLF in the committed version but git add will strip the \r. In other words, with eol=lf, if the committed file has \r\n, git add foo.bar would change it to \n, so the work-tree version (which also has \r\n right now) won't match the "intended next commit if file is added", so the index-vs-work-tree will be considered different/dirty. (I think this is why the Git docs recommend a mass-re-commit at this point.)Chokedamp
Let us continue this discussion in chat.Okay

© 2022 - 2024 — McMap. All rights reserved.