--- UPDATE 3 --- (does not conflict with UPDATE 2)
Considering the case that windows users prefer working on CRLF
and linux/mac users prefer working on LF
on text files. Providing the answer from the perspective of a repository maintainer:
For me the best strategy(less problems to solve) is: keep all text files with LF
inside git repo even if you are working on a windows-only project. Then give the freedom to clients to work on the line-ending style of their preference, provided that they pick a core.autocrlf
property value that will respect your strategy (LF on repo) while staging files for commit.
Staging is what many people confuse when trying to understand how newline strategies work. It is essential to undestand the following points before picking the correct value for core.autocrlf
property:
- Adding a text file for commit (staging it) is like copying the file to another place inside
.git/
sub-directory with converted line-endings (depending on core.autocrlf
value on your client config). All this is done locally.
- setting
core.autocrlf
is like providing an answer to the question (exact same question on all OS): "Should git-client:
- a. convert LF-to-CRLF when checking-out (pulling) the repo changes from the remote?
- b. convert CRLF-to-LF when adding a file for commit?"
- and the possible answers (values) are:
false:
"do none of the above",
input:
"do only b"
true
: "do a and and b"
- note that there is NO "do only a"
Fortunately
- git client defaults (windows:
core.autocrlf: true
, linux/mac:
core.autocrlf: false
) will be compatible with LF-only-repo strategy.
Meaning: windows clients will by default convert to CRLF when checking-out the repository and convert to LF when adding for commit. And linux clients will by default not do any conversions. This theoretically keeps your repo lf-only.
Unfortunately:
- There might be GUI clients that do not respect the git
core.autocrlf
value
- There might be people that don't use a value to respect your lf-repo strategy. E.g. they use
core.autocrlf=false
and add a file with CRLF for commit.
To detect ASAP non-lf text files committed by the above clients you can follow what is described on --- update 2 ---: (git grep -I --files-with-matches --perl-regexp '\r' HEAD
, on a client compiled using: --with-libpcre
flag)
And here is the catch:. I as a repo maintainer keep a git.autocrlf=input
so that I can fix any wrongly committed files just by adding them again for commit. And I provide a commit text: "Fixing wrongly committed files".
As far as .gitattributes
is concearned. I do not count on it, because there are more ui clients that do not understand it. I only use it to provide hints for text and binary files, and maybe flag some exceptional files that should everywhere keep the same line-endings:
*.java text !eol # Don't do auto-detection. Treat as text (don't set any eol rule. use client's)
*.jpg -text # Don't do auto-detection. Treat as binary
*.sh text eol=lf # Don't do auto-detection. Treat as text. Checkout and add with eol=lf
*.bat text eol=crlf # Treat as text. Checkout and add with eol=crlf
Question: But why are we interested at all in newline handling strategy?
Answer: To avoid a single letter change commit, appear as a 5000-line change, just because the client that performed the change auto-converted the full file from crlf to lf (or the opposite) before adding it for commit. This can be rather painful when there is a conflict resolution involved. Or it could in some cases be the cause of unreasonable conflicts.
--- UPDATE 2 ---
The dafaults of git client will work in most cases. Even if you only have windows only clients, linux only clients or both. These are:
- windows:
core.autocrlf=true
means convert lines to CRLF on checkout and convert lines to LF when adding files.
- linux:
core.autocrlf=input
means don't convert lines on checkout (no need to since files are expected to be committed with LF) and convert lines to LF (if needed) when adding files.
(-- update3 -- : Seems that this is false
by default, but again it is fine)
The property can be set in different scopes. I would suggest explicitly setting in the --global
scope, to avoid some IDE issues described at the end.
git config core.autocrlf
git config --global core.autocrlf
git config --system core.autocrlf
git config --local core.autocrlf
git config --show-origin core.autocrlf
Also I would strongly discourage using on windows git config --global core.autocrlf false
(in case you have windows only clients) in contrast to what is proposed to git documentation. Setting to false will commit files with CRLF in the repo. But there is really no reason. You never know whether you will need to share the project with linux users. Plus it's one extra step for each client that joins the project instead of using defaults.
Now for some special cases of files (e.g. *.bat
*.sh
) which you want them to be checked-out with LF or with CRLF you can use .gitattributes
To sum-up for me the best practice is:
- Make sure that every non-binary file is committed with LF on git repo (default behaviour).
- Use this command to make sure that no files are committed with CRLF:
git grep -I --files-with-matches --perl-regexp '\r' HEAD
(Note: on windows clients works only through git-bash
and on linux clients only if compiled using --with-libpcre
in ./configure
).
- If you find any such files by executing the above command, correct them. This in involves (at least on linux):
- set
core.autocrlf=input
(--- update 3 --)
- change the file
- revert the change(file is still shown as changed)
- commit it
- Use only the bare minimum
.gitattributes
- Instruct the users to set the
core.autocrlf
described above to its default values.
- Do not count 100% on the presence of
.gitattributes
. git-clients of IDEs may ignore them or treat them differrently.
As said some things can be added in git attributes:
# Always checkout with LF
*.sh text eol=lf
# Always checkout with CRLF
*.bat text eol=crlf
I think some other safe options for .gitattributes
instead of using auto-detection for binary files:
-text
(e.g for *.zip
or *.jpg
files: Will not be treated as text. Thus no line-ending conversions will be attempted. Diff might be possible through conversion programs)
text !eol
(e.g. for *.java
,*.html
: Treated as text, but eol style preference is not set. So client setting is used.)
-text -diff -merge
(e.g for *.hugefile
: Not treated as text. No diff/merge possible)
--- PREVIOUS UPDATE ---
One painful example of a client that will commit files wrongly:
netbeans 8.2 (on windows), will wrongly commit all text files with CRLFs, unless you have explicitly set core.autocrlf
as global. This contradicts to the standard git client behaviour, and causes lots of problems later, while updating/merging. This is what makes some files appear different (although they are not) even when you revert.
The same behaviour in netbeans happens even if you have added correct .gitattributes
to your project.
Using the following command after a commit, will at least help you detect early whether your git repo has line ending issues: git grep -I --files-with-matches --perl-regexp '\r' HEAD
I have spent hours to come up with the best possible use of .gitattributes
, to finally realize, that I cannot count on it.
Unfortunately, as long as JGit-based editors exist (which cannot handle .gitattributes
correctly), the safe solution is to force LF everywhere even on editor-level.
Use the following anti-CRLF
disinfectants.
windows/linux clients: core.autocrlf=input
committed .gitattributes
: * text=auto eol=lf
committed .editorconfig
(http://editorconfig.org/) which is kind of standardized format, combined with editor plugins:
.gitattributes
does GitHub for Windows suggests for your project? I installed GitHub for Windows, started the GUI version and was unable to find any option related with.gitattributes
suggestions. – Bragg