1

This is essentially a follow-up to the question asked here about the difference between * text=auto and * text=auto eol=lf in a .gitattributes config: What is the difference between "* text=auto" and "* text=auto eol=lf"?

I think I understand how Git works, but I'd like confirmation because the docs are confusing.

The docs for the text attribute state:

This attribute enables and controls end-of-line normalization. When a text file is normalized, its line endings are converted to LF in the repository. 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. Note that setting core.autocrlf to true or input overrides core.eol (see the definitions of those options in git-config[1]).

So it sounds like Git enforces LF by default if you use * text=auto, making * text=auto eol=lf redundant.

However, the second bolded part of the quote is what's confusing me: Does Git ever respect core.autocrlf or core.eol? I tested this on a Windows machine using PowerShell and Git 2.16.1:

  1. Run git config --global core.autocrlf false and git config --global core.eol crlf. The latter is not what you'd usually want, but it's useful for this experiment to see if Git even picks it up at all.
  2. Create a text file using Notepad with multiple lines of content. The file should have CRLF line endings.
  3. Initialize a Git repo in the same directory.
  4. Add the file to Git's index.
  5. Run git ls-files --eol and observe that the file has CRLF in both the index and working tree.
  6. Add a .gitattributes file with * text = auto. Commit it.
  7. Run git add --renormalize . to renormalize the previously committed file.
  8. Run git status. Observe that the file has been staged for commit.
  9. After committing the file, run git ls-files --eol to observe that the file now uses LF in the index.

So despite me setting core.eol=crlf and turning off core.autocrlf, Git still enforced LF for line endings.

Question: Are the docs misleading? Will text=auto always enforce LF?

1 Answers1

0

I think I figured it out:

  • core.autocrlf and core.eol only impact line endings in the working tree, not in Git's index (which will always use LF when normalization is enabled) or the remote copy of your code. Hence the output of git ls-files --eol.

  • The eol attribute in .gitattributes implies text, which means it enforces LF in the index and whatever value you've set for eol in the working directory. Example: eol=crlf implies index = LF and working tree = CRLF.

So the docs are slightly misleading in that text=auto does NOT rely on core.autocrlf or core.eol—it always enforces LF line endings for the index. Line endings in the working tree are left as-is unless you configure core.autocrlf, core.eol, or use the eol attribute.

  • That's not quite right: bk2204 notes that `eol=lf` or `eol=crlf` forces `text` to be fully set (not just set to auto): see [this question](https://stackoverflow.com/q/70633469/1256452). This behavior changed between Git 2.9 and 2.10, apparently. – torek Jan 12 '22 at 01:25
  • Hm: According to the release notes, `* text=auto eol=lf` meant `* text eol=lf` in Git 2.9 an earlier, but no longer does in 2.10 and later, so that was considered to be a bug. Since you're on Git 2.16 you won't have this bug, presumably. – torek Jan 12 '22 at 01:31
  • In any case, *if* the file *is* detected as text, the `eol=` setting will indeed always normalize the index copy to have LF-only, as you said. However, *if* Git decides that the file is binary, the index copy won't be tweaked. – torek Jan 12 '22 at 01:32
  • @torek Right, I'm mainly concerned about modern Git versions. The way I understood it, `eol` implies `text`. Whenever `text` is used, line endings in the index become `LF`. If `text=auto` (with or without an `eol` attribute), Git will use its auto-detection algorithm to only apply this normalization to text files. Then, `eol`'s primary function is to change the line endings in the working directory. – Aleksandr Hovhannisyan Jan 12 '22 at 12:08
  • `=auto` does not _rely_ on `core.autocrlf` or `core.eol`, it _defers_ to them. `core.eol` is only used on checkout, and only if `core.autocrlf=false` or unset. – mkjeldsen Feb 06 '22 at 19:03