Platform: Windows 8.1 Emacs 24.3
The git config --global -l shows:
user.name=username
user.email=useremail
core.autocrlf=false
core.safecrlf=true
Git repository .gitattributes file:
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
I do think my Git and repository settings are right.
But everytime I create a new text file with Emacs, I cannot run git add <newfile>. The file is encoded by utf-8-unix.
The error message is as:
E:\workspace\repository [master +0 ~2 -0]> git add .
fatal: LF would be replaced by CRLF in newfile.txt
I don't think is due to emacs editor problem. Because I opened the new file and pretty sure the line ending is LF not the windows default CRLF.
Which configuration part decides LF will be replaced by CRLF?
EDIT 1
If safecrlf is set to warn the output is:
warning: LF will be replaced by CRLF in _posts/2014-11-19-test.md.
The file will have its original line endings in your working directory.
This means that the file was successfully added to the index. My file is encoded by utf-8-unix.
EDIT 2
Interestingly, if I create a new file with Notepad not the Emacs 24.3, the file can be added without any problem. The difference is Notepad adopts CRLF line ending while Emacs 24.3 adopts LF line ending.
So the problem is somewhere somehow Git converts CRLF to LF then back to CRLF which generates error for original LF line ending file.
EDIT 3
Previously, GitHub Windows GUI client warned me no .gitattributes file for my repository and recommend a default .gitattributes file as above.
I think the problem is from the line * text=auto. So I comment out this line.
Everything works good now!
EDIT 4
The core is:
DISABLE AUTO LINE ENDING CONVERSION by GitHub.
DEPEND ON PLATFORM FILE EDITOR FOR LINE ENDING.
EDIT 5
textThis attribute enables and controls end-of-line normalization. When a text file is normalized, its line endings are converted toLFin the repository. To control what line ending style is used in the working directory, use theeolattribute for a single file and thecore.eolconfiguration variable for all text files.- Setting the
textattribute on a path enables end-of-line normalization and marks the path as a text file. End-of-line conversion takes place without guessing the content type. - Unsetting the
textattribute on a path tells Git not to attempt any end-of-line conversion upon checkin or checkout. - When
textis set to "auto", the path is marked for automatic end-of-line normalization. If Git decides that the content is text, its line endings are normalized toLFon checkin. - Unspecified. If the
textattribute is unspecified (by!textor no setting entry at all), Git uses thecore.autocrlfconfiguration variable to determine if the file should be converted (fall-back compatibility as noted in EDIT 8).
- Setting the
eolThis attribute sets a specific line-ending style to be used in the working directory. It enables end-of-line normalization without any content checks, effectively setting thetextattribute.- That is to say
eolautomatically settextattribute. - Set to string value "crlf"
This setting forces Git to normalize line endings for this file on checkin and convert them to CRLF when the file is checked out. - Set to string value "lf"
This setting forces Git to normalize line endings to LF on checkin and prevents conversion to CRLF when the file is checked out.
- That is to say
If eol is put in .gitattributes file, it should be applied to specific file type. At the same time, it automatically marks the specific file type as text at the same time for LF normalization when checkin. If eol is set as git config --global core.eol xxx, then eol is set for all text files.
Refer to gitattributes - defining attributes per path
EDIT 6
Git attributes are specified in .gitattributes files. Line endings are controlled by text and eol attributes.
text attribute tells Git whether the file is binary (i.e. no EOL conversion should be performed while checking out and in) or text (perform EOL conversion, always convert to LF while checking in). Possible values are set (EOLs conversion is turned on), unset(EOLs conversion is turned off, default value) and auto(if the file is detected as binary, no conversion, otherwise EOLs conversion is performed).
eol attribute: if set implicitly sets text attribute and defines EOL to which the file should be converted while checking out.
Refer to Line endings handling in SVN, Git and SubGit
EDIT 7
Possible solutions:
- As EDIT 3, comment out
* text=auto - Add a line in
gitattributesfor.mdfile:*.md eol=lf- If another kind of text file such as
.txtis created, I should also add a line for it*.txt eol=lf
- If another kind of text file such as
- Change
* text=autoto* !text - Totally remove the
.gitattributesfile
To my current knowledge I think:
- By
filetype textingitattributes, EOL normalization is carried out forfiletypeat checkin. - AT THE SAME TIME, this line implicates that
default eolshould also be carried out when checkout.defaultmeans depending on global configuration asgit config --global core.eol xxxor default operating system style ascore.eol = native.- You can run
git config --global core.eolto see what this value is set to on your system. If nothing comes back that means you are on the using the OS default which isnative.
- You can run
- eol implicates
textattribute, whiletextimplicates defaulteolattribute. - So when
*.md text=autois enabled.*.mdfile is detected by Git astextfile and converted to LF when checkin. When checkout,*.mdLF will be converted to CRLF. This process is invalidated bysafecrlf = falseglobal setting, refusing to adding the file to index/stage area.
EDIT 8
My three assumptions in EDIT 7 is verified Mind the End of Your Line
Since Git 1.7.2 and above, EOL settings are mainly put in .gitattributes in the root directory of working tree. The global config autocrlf is only for fall-back compatibility.
*.txt text Set all files matching the filter *.txt to be text. This means that Git will run CRLF to LFreplacement on these files every time they are written to the object database and the reverse replacement will be run when writing out to the working directory.
EDIT 9 Final Idea
textandcore.autocrlf(in.gitattributes) focuses on EOL conversion writing to repository database from working tree.eolandcore.eol(inglobal config) focuses on EOL conversion writing to working tree from repository database..gitattributeshas higher precedence thanglobal configwhen deciding EOL conversion. The later one is actually fall-back reference.- If one way conversion is specified, the other way is unspecified or undefined, the default fall-back option is used for the other way conversion.
- The EOL issue associates closely with which line ending you choose when editing files.
For logical explanation refer to my blog znhoo
The culprit is the
core.safecrlf=truein your Git config.From the git-config manual page: