Update 04/17/2012: After reading the article by Tim Clem linked by JJD in the comments, I have modified some of the values in the "unknown" values in the table above, as well as changing "checkout existing | true to convert to CRLF instead of convert to client". Here are the definitions he gives, which are more clear than anything I've seen elsewhere:
core.autocrlf = false
This is the default, but most people are encouraged to change this immediately. The result of using false is that Git doesn’t ever mess with line endings on your file. You can check in files with LF or CRLF or CR or some random mix of those three and Git does not care. This can make diffs harder to read and merges more difficult. Most people working in a Unix/Linux world use this value because they don’t have CRLF problems and they don’t need Git to be doing extra work whenever files are written to the object database or written out into the working directory.
core.autocrlf = true
This means that Git will process all text files and make sure that CRLF is replaced with LF when writing that file to the object database and turn all LF back into CRLF when writing out into the working directory. This is the recommended setting on Windows because it ensures that your repository can be used on other platforms while retaining CRLF in your working directory.
core.autocrlf = input
This means that Git will process all text files and make sure that CRLF is replaced with LF when writing that file to the object database. It will not, however, do the reverse. When you read files back out of the object database and write them into the working directory they will still have LFs to denote the end of line. This setting is generally used on Unix/Linux/OS X to prevent CRLFs from getting written into the repository. The idea being that if you pasted code from a web browser and accidentally got CRLFs into one of your files, Git would make sure they were replaced with LFs when you wrote to the object database.
Tim's article is excellent, the only thing I can think of that is missing is that he assumes the repository is in LF format, which is not necessarily true, especially for Windows only projects.
Comparing Tim's article to the highest voted answer to date by jmlane shows perfect agreement on the true and input settings and disagreement on the false setting.
This is how
core.autocrlf appears to work currently (or at least since v1.7.2 from what I am aware):
core.autocrlf = true
- Text files checked-out from the repository that have only
LFcharacters are normalized to
CRLFin your working tree; files that contain
CRLFin the repository will not be touched
- Text files that have only
LFcharacters in the repository, are normalized from
LFwhen committed back to the repository. Files that contain
CRLFin the repository will be committed untouched.
core.autocrlf = input
- Text files checked-out from the repository will keep original EOL characters in your working tree.
- Text files in your working tree with
CRLFcharacters are normalized to
LFwhen committed back to the repository.
core.autocrlf = false
core.eoldictates EOL characters in the text files of your working tree.
core.eol = nativeby default, which means Windows EOLs are
CRLFand *nix EOLs are
LFin working trees.
gitattributessettings determines EOL character normalization for commits to the repository (default is normalization to
I've only just recently researched this issue and I also find the situation to be very convoluted. The
core.eol setting definitely helped clarify how EOL characters are handled by git.
The issue of EOLs in mixed-platform projects has been making my life miserable for a long time. The problems usually arise when there are already files with different and mixed EOLs already in the repo. This means that:
- The repo may have different files with different EOLs
- Some files in the repo may have mixed EOL, e.g. a combination of
LFin the same file.
How this happens is not the issue here, but it does happen.
I ran some conversion tests on Windows for the various modes and their combinations.
Here is what I got, in a slightly modified table:
| Resulting conversion when | Resulting conversion when | committing files with various | checking out FROM repo - | EOLs INTO repo and | with mixed files in it and | core.autocrlf value: | core.autocrlf value: -------------------------------------------------------------------------------- File | true | input | false | true | input | false -------------------------------------------------------------------------------- Windows-CRLF | CRLF -> LF | CRLF -> LF | as-is | as-is | as-is | as-is Unix -LF | as-is | as-is | as-is | LF -> CRLF | as-is | as-is Mac -CR | as-is | as-is | as-is | as-is | as-is | as-is Mixed-CRLF+LF | as-is | as-is | as-is | as-is | as-is | as-is Mixed-CRLF+LF+CR | as-is | as-is | as-is | as-is | as-is | as-is
As you can see, there are 2 cases when conversion happens on commit (3 left columns). In the rest of the cases the files are committed as-is.
Upon checkout (3 right columns), there is only 1 case where conversion happens when:
- the file in the repo has the
Most surprising for me, and I suspect, the cause of many EOL problems is that there is no configuration in which mixed EOL like
LF get normalized.
Note also that "old" Mac EOLs of
CR only also never get converted.
This means that if a badly written EOL conversion script tries to convert a mixed ending file with
LFs, by just converting
CRLFs, then it will leave the file in a mixed mode with "lonely"
CRs wherever a
CRLF was converted to
Git will then not convert anything, even in
true mode, and EOL havoc continues. This actually happened to me and messed up my files really badly, since some editors and compilers (e.g. VS2010) don't like Mac EOLs.
I guess the only way to really handle these problems is to occasionally normalize the whole repo by checking out all the files in
false mode, running a proper normalization and re-committing the changed files (if any). On Windows, presumably resume working with
core.autocrlf value does not depend on OS type but on Windows default value is
true and for Linux -
input. I explored 3 possible values for commit and checkout cases and this is the resulting table:
╔═══════════════╦══════════════╦══════════════╦══════════════╗ ║ core.autocrlf ║ false ║ input ║ true ║ ╠═══════════════╬══════════════╬══════════════╬══════════════╣ ║ ║ LF => LF ║ LF => LF ║ LF => LF ║ ║ git commit ║ CR => CR ║ CR => CR ║ CR => CR ║ ║ ║ CRLF => CRLF ║ CRLF => LF ║ CRLF => LF ║ ╠═══════════════╬══════════════╬══════════════╬══════════════╣ ║ ║ LF => LF ║ LF => LF ║ LF => CRLF ║ ║ git checkout ║ CR => CR ║ CR => CR ║ CR => CR ║ ║ ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║
Things are about to change on the "eol conversion" front, with the upcoming Git 1.7.2:
A new config setting
core.eol is being added/evolved:
This is a replacement for the 'Add "
core.eol" config variable' commit that's currently in
pu(the last one in my series).
Instead of implying that "
core.autocrlf=true" is a replacement for "
* text=auto", it makes explicit the fact that
autocrlfis only for users who want to work with CRLFs in their working directory on a repository that doesn't have text file normalization.
When it is enabled, "core.eol" is ignored.
Introduce a new configuration variable, "
core.eol", that allows the user to set which line endings to use for end-of-line-normalized files in the working directory.
It defaults to "
native", which means CRLF on Windows and LF everywhere else. Note that "
This means that:
[core] autocrlf = true
puts CRLFs in the working directory even if
core.eolis set to "
Sets the line ending type to use in the working directory for files that have the
Alternatives are 'lf', 'crlf' and 'native', which uses the platform's native line ending.
The default value is
Other evolutions are being considered:
For 1.8, I would consider making
core.autocrlfjust turn on normalization and leave the working directory line ending decision to core.eol, but that will break people's setups.
git 2.8 (March 2016) improves the way
core.autocrlf influences the eol:
See commit 817a0c7 (23 Feb 2016), commit 6e336a5, commit df747b8, commit df747b8 (10 Feb 2016), commit df747b8, commit df747b8 (10 Feb 2016), and commit 4b4024f, commit bb211b4, commit 92cce13, commit 320d39c, commit 4b4024f, commit bb211b4, commit 92cce13, commit 320d39c (05 Feb 2016) by Torsten Bögershausen (
(Merged by Junio C Hamano --
gitster -- in commit c6b94eb, 26 Feb 2016)
Refactor the determination and usage of
Today, when no "
crlf" attribute are set on a file,
crlf_actionis set to
CRLF_UNDEFINEDinstead, and search for "
text" or "
eol" as before.
Replace the old
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf and core.eol is evaluated and one of CRLF_BINARY, CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected - CRLF_BINARY : No processing of line endings. - CRLF_TEXT : attribute "text" is set, line endings are processed. - CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text. - CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text. - CRLF_AUTO : attribute "auto" is set. - CRLF_AUTO_INPUT: core.autocrlf=input (no attributes) - CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
all these translations (any EOL conversion from
autocrlfsettings, and "
clean" filters) are run when files move from work-tree to index, i.e., during
git addrather than at
git commit -aor
--includedo add files to the index at that time, though.)
For more on that, see "What is difference between autocrlf and eol".