How to change line-ending settings
The normal way to control this is with git config
For example
git config --global core.autocrlf true
For details, scroll down in this link to Pro Git to the section named "core.autocrlf"
If you want to know what file this is saved in, you can run the command:
git config --global --edit
and the git global config file should open in a text editor, and you can see where that file was loaded from.
Git - Windows AND linux line-endings
On Windows:
$ git config --global core.autocrlf true
On Linux:
$ git config --global core.autocrlf input
Read more about Dealing with line endings
Git - Use Linux-style Line Endings on Linux and Windows-style Line Endings on Windows
Git by default performs line ending conversions on text files. If you want files to have their line endings converted, you can mark them as text by flagging them in your .gitattributes
file:
*.cs text
If you'd like Git to guess about which files are text automatically, then you should write something like this:
* text=auto
Assuming your build agents do not have custom Git configuration that overrides line endings, that should be sufficient for Git to convert line endings to the native ones. If you'd like to be explicit, you can perform the clone with core.eol
set to native
, like so: git -c core.eol=native clone URL
.
However, having said that, it's generally not a good idea in your code to make assumptions about line endings. If your users are using the Windows Subsystem for Linux, they may well be using a Unix Git and use Unix line endings in their working tree, and that shouldn't affect the correctness of your unit tests. Line endings should be set either explicitly to LF or CRLF because of functional reasons (e.g., shell scripts won't work with CRLF endings on any platform) or left to the user's desires based on their development environment.
If you need to explicitly use the platform's native line endings in a test, you should write an explicit string that will be parsed appropriately based on the platform, or wrap your test strings in a helper function that converts them based on the platform.
How can I use `LF` line endings in Git for Windows in 2020 for good?
There are two git config attributes that affect the line endings: core.autocrlf
and core.eol
.
Previously, you were told to use core.autocrlf = true
to be able to work on cross-platform projects, but it's not true
any more.
If your system/IDE/tooling support LF
and you do want to use LF
as everyone else in your team without any silent lf->crlf->lf
normalizations, you must turn off autocrlf
and configure eol
to not infer native
line endings, but force it to use lf
.
Now there are two ways to achieve LF
in all your files a/o repos:
- Globally for all repositories on your local machine.
- Per-repository via checked-in
.gitattributes
file.
This file overrides any local configuration for everyone who clones the repo.
I personally recommend to go with both for all local repos and to ensure cross-platform cross-dev consistency.
1) Globally for all repositories on your local machine
Being in your working directory (your local repo):
First commit everything
Let's be paranoid a bit and set it both globally and in repo as well. Just in case.
git config --global core.eol lf
git config --global core.autocrlf false
git config core.eol lf
git config core.autocrlf falseDelete everything "code" except
.git
.
You can also omit dependencies, installed files (such asnode_modules
), build files and any git-ignored file as well.and lastly run
git reset --hard HEAD
Things should be working now. Newly checked files should follow the new configuration and keep whatever line-endings were cloned from the remote repo.
Note that if your remote repo uses mix of crlf
lf
endings, you will also have to run and push
git add --renormalize .
2) Per-repository via checked-in .gitattributes
file
Being in your working directory (your local repo):
Create
.gitattributes
file in the root with this content:* text=auto eol=lf
Commit the file (and everything else)
Same as above
Same as above
IMPORTANT NOTE: After you introduce the file into the repository, it is necessary that everyone who still has old CRLF files does step 3 and 4 to update their working directory as just checking out the commit doesn't affect already existing files.
Notes
setting core.autocrlf
to true
or input
overrides core.eol
https://www.git-scm.com/docs/git-config#Documentation/git-config.txt-coreautocrlf
core.autocrlf = input
is the preferred value on unix systems.
https://stackoverflow.com/a/41282375/985454
https://stackoverflow.com/a/4425433/985454
Troubleshooting
Reinstall git for windows with third option (as in the screenshot in Q)
Checkout as is - Commit as is (
core.autocrlf = false
)
git: always force windows line endings for repo
First, you have two conflicting settings. * text=auto
and * text eol=crlf
are not compatible. You need to pick one.
However, I regret that neither will do what you want. Git has no option that is "always convert to CR/LF in the repository". Your only options control what goes into the working directory.
For example, * text eol=crlf
will put Windows-style line endings in the working directory but will put Unix-style line in the repository.
You can disable line ending configuration entirely by using * -text
, but this will simply stop doing text conversion and check in the file literally as it exists on disk. It does not eliminate the possibility of a Unix user rewriting the file with Unix-style line endings.
I would encourage you to ignore the contents of the file that exists in the repository, and focus on what you want in working directories instead. If you always want CR/LF on disk then use * text eol=crlf
.
Git CRLF and LF line ending on windows/linux
Don't forget to add a .gitattributes
rule for that file, in order to force lf for that file
a_file text=auto eol=lf
But regarding your send-email issue, see "git am/format-patch
: control format of line endings", try and use git send-email --transfer-encoding=base64
, to make sure everything is preserved (including eol)
How to change the line ending in a Git repo dynamically
But my files are still having the CRLF line ending.
If a file inside a commit inside the repository has CRLF line endings, that version of that file is stuck that way forever. No part of any existing commit can ever be changed.
If a file inside a commit inside the repository has LF-only line endings, that version of that file is stuck that way forever. However, you can can choose the ending you want to have Git place in your work-tree when you extract that file.
If you already extracted the file, Git has already done the conversion. Git now thinks everything is fine, even if you just now changed the conversion setting.
Thus, if you change the conversion setting, you must force Git to re-extract the file. The easiest way to do this consistently in all versions of Git is to remove the file from your work-tree, then run git checkout -- path/to/file
. Because the file is gone from the work-tree, Git will be forced to extract it again. The updated EOL-conversion will be applied this time.
(Another way to do it is to alter the file, then run the same git checkout
, or in Git 2.23 or later, to use git restore
. By telling Git that Git should discard your version of the file, and Git seeing that your version of the file is indeed "wrong" in that it doesn't match the index copy because you changed it, Git will be forced to re-extract the index copy.)
That may suffice for you case, or may not. If it does not, read on.
What to know about Git's end-of-line conversions
I'm a firm believer in the "never use Windows at all so that you never need to have your version control system muck with line endings" philosophy myself, but there are a few things to know if you are in some other camp and do want Git to muck with line endings. The most important of these is this: What you store in Git, and what you use when you work with files you got out of Git, are not necessarily the same thing.
To see how this works, remember that Git stores commits rather than directly storing files. The files inside those commits come from Git's index, not from your work-tree. The format of an index-copy of a file is the same as the internal format that Git uses for frozen-for-all-time commits: the data are pre-compressed. So the copy of each file that's in the index is already significantly different from the copy you use in your work-tree, in that the one in your work-tree is not a Git blob object, and generally not zlib-compressed.
Git reads commits into the index before copying them out to your work-tree. Running git add
on a file compresses and blob-ifies the file in order to store it in Git's index. Right at this point of conversion, while Git is compressing and Git-ifying a file (git add
) or de-Git-ifying and decompressing a file (git checkout-index
or equivalent), it's trivial for Git to insert additional conversion operations.
Git therefore does its thing at this point. The things that Git can do—the only things built in directly—are that, on the way out of the index, Git can replace \n
-only line endings with \r\n
line endings, and on the way into the index, Git can replace \r\n
line endings with \n
-only line endings.
In other words, you can arrange for Git to throw away some carriage returns before storing a file, and to add some carriage returns when extracting a file. If you do both of these, you get CRLF line endings in your work-tree and newline-only line endings in the commits.
You can, if you like, have Git do only one of these: in particular, with the crlf=input
setting, you can tell Git: do just one conversion, on the work-tree-to-index copy operation.
If you choose to have Git do conversions when extracting files, the only conversion available here is turn LF-only into CRLF. You cannot turn CRLF endings into LF-only endings. If the in-Git committed file has CRLF endings, the in-work-tree extracted file will have CRLF endings.
Again, each of these conversions happens in just one direction:
- index → work-tree: optionally, replace
\n
with\r\n
- work-tree → index: optionally, replace
\r\n
with\n
What you choose with core.autocrlf
or .gitattributes
directives are:
text
,-text
, and/orcore.autocrlf
: which fileseol=...
and/orcore.eol
: get which treatment(s)crlf=input
: on which operation(s)
Once a file has been treated and converted—by copying it to or from the index—Git marks the index's copy as "matches the work-tree's copy" by grabbing key data from the OS: the file's size and other lstat
system call values. The precise details here vary because different OSes store different data with different granularity.
The easy way to force a new conversion is to remove one or the other copy of the file: rm file
or git rm --cached file
destroys the work-tree or index copy respectively, so now a git checkout -- file
or git add file
will make a new one.
When you run git commit
, whatever bytes are in the index copy of the file go into the new commit that Git makes. This new commit is now frozen for all time: the bytes that were in the index are now in the commit, forever (or for as long as the commit itself continues to exist). Nothing and no one can change them.
Consequences of the above
What the above mean is that if you do plan to have your version control system (i.e., Git) muck about with line endings, the line endings you can—and thus probably should—always use for every index copy, and therefore every committed copy, of every text file are LF-only line endings. These can always be converted to CRLF endings in a work-tree file, through an appropriate .gitattributes
setting or core.*
settings. If you've done such a conversion, that work-tree file can be converted back to LF-only line endings on git add
operations.
If you ever do commit a file with CRLF line endings, that commit is stuck that way for all time, and extracting that commit will give you a work-tree copy that has CRLF line endings, every time, because Git has no built in index → work-tree operation that will change this. The only built in CRLF-to-LF operation that Git has only works in the other direction, index ← work-tree.
If you'd like to make a new and improved commit in which the committed copy of that file has LF-only line endings, you have these two options:
- make sure your index ← work-tree settings do that, then force Git to add the file (e.g., change it in the work-tree or use
git rm --cached
on the index copy, andgit add
it); or - use any command that changes the work-tree copy to have LF-only line endings, e.g., run
dos2unix
on it or similar, thengit add
it.
The advantage to method 2 is that you can see the effect immediately (in your work-tree file) and it's hard to get it wrong. The problem with method 1 is that you can't see it, and it's easy to get it totally wrong: e.g., you might accidentally use git rm
instead of git rm --cached
, which deletes both the index and work-tree copies.
How to force consistent line endings in Git commits with cross-platform compatibility
Q1 Enforcing consistent lineendings
Q2 Enforcing at commit as well as checkout (comment)
I'll divide this into 2 parts: Practice and Principle
Practice
Expansion of code-apprentice's suggestion
- Strictly avoid
autocrlf
— See why autocrlf is always wrong.
And here for the core git devs arguing about the ill-thoughtout-ness of autocrlf. Note particularly that the implementor is annoyed at the critic but doesn't deny the criticism. - Religiously use
.gitattributes
instead - Use
safecrlf=true
to enforce commit-cleanliness.safecrlf
is the answer to your Q2 – a file that would change on check-in check-out round tripping would error out on the check-in stage itself.
When a new repo is init-ed:
Go through ls -lR
and choose for it's type text, binary
or ignore (ie put it in .gitignore)
Debugging:
Use git-check-attr to check that attribute matching and computation are as desired
Principle
Data Store
We may treat git as a data-store loosely analogous to how a USB drive is one.
We say the drive is working if the stuff we put in comes out the same. Else it's corrupted. Likewise if the file we commit comes out the same on checkout the repo is fine else (something) is borked. The key question is
What does "same" mean?
It's non-trivial because we implicitly apply different standards of "sameness" in different contexts!
Binary Files
- A binary file is a sequence of bytes
- Preserving that sequence faithfully amounts to reproducing the file
Text Files
...are different
A text file consists of a sequence of «printable characters» — let's leave the printable char notion unspecified other than to say no cr no lf!
How these lines are separated (or terminated) is again unspecified
Symbolically:
type Line = [Char]
type File = [Line]Expanding on the 1st unspecified gives us ASCII, Latins, Unicode etc etc... Not relevant to this question
Expanding on the 2nd is what distinguishes windows *nix etc. JFTR this kind of file may be little known by the younger generation but also exists. And is particularly useful to remember that the notion "sequence of lines" can be imposed at many different levels.
We don't care how the sameness respects the unspecified parts
To return to our
USB drive analogy
When I copy foo.txt from Windows to Linux I expect the contents to be invariant. However I'm quite satisfied if H:foo.txt
changes to /media/name/Transcend/foo.txt
. In fact it would be more than a bit annoying if the windowsisms came through untranslated or vice versa.
Far-fetched?? ¡¡Think again!!
IOW thanks to splendid folks like Theodore T'so we take it for granted that Linux can read a windows file (system). This happens because a non-trivial amt of
- abstraction matching
- abstraction hiding
happens under the hood.
Back to Git
We therefore expect that a file checked in to git is the same that's checked out... at a different time... And OS!
The catch is that the notion of same is sufficiently non-trivial that git needs some help from us in achieving that "sameness" to our satisfaction... That help is called .gitattributes!
Related Topics
Change Filenames to Lowercase in Ubuntu in All Subdirectories
Linux - Write Commands from One Terminal to Another
Ssh Command Execution Hangs, Although Interactive Shell Functions Fine
Simulate Network Latency on Specific Port Using Tc
Calculating Rounded Percentage in Shell Script Without Using "Bc"
Critical Timing in an Arm Linux Kernel Driver
How to "Expect" and "Send" After "Interact" Command
Cmake:How to Change File Permissions When Installing
How to Connect to Jenkins Server (Amazon Linux Ami)
Linux' Hrtimer - Microsecond Precision
Sed: How to Delete Lines Matching a Pattern That Contains Forward Slashes
Pause Programmatically Video Player Mpv
Determine If Relative or Absolute Path in Shell Program
Mapping Physical Addresses to Virtual Address Linux
Can Malloc_Trim() Release Memory from the Middle of the Heap