What's the best CRLF (carriage return, line fe

2018-12-31 14:13发布

问题:

I tried committing files with CRLF-ending lines, but it failed.

I spent a whole work day on my Windows computer trying different strategies and was almost drawn to stop trying to use Git and instead try Mercurial.

Please share only one best practice per answer.

回答1:

Almost four years after asking this question, I have finally found an answer that completely satisfies me!

See the details in github:help\'s guide to Dealing with line endings.

Git allows you to set the line ending properties for a repo directly using the text attribute in the .gitattributes file. This file is committed into the repo and overrides the core.autocrlf setting, allowing you to ensure consistent behaviour for all users regardless of their git settings.

And thus

The advantage of this is that your end of line configuration now travels with your repository and you don\'t need to worry about whether or not collaborators have the proper global settings.

Here\'s an example of a .gitattributes file

# Auto detect text files and perform LF normalization
*        text=auto

*.cs     text diff=csharp
*.java   text diff=java
*.html   text diff=html
*.css    text
*.js     text
*.sql    text

*.csproj text merge=union
*.sln    text merge=union eol=crlf

*.docx   diff=astextplain
*.DOCX   diff=astextplain

# absolute paths are ok, as are globs
/**/postinst* text eol=lf

# paths that don\'t start with / are treated relative to the .gitattributes folder
relative/path/*.txt text eol=lf

There is a convenient collection of ready to use .gitattributes files for the most popular programming languages. It\'s useful to get you started.

Once you\'ve created or adjusted your .gitattributes, you should perform a once-and-for-all line endings re-normalization.

Note that the GitHub Desktop app can suggest and create a .gitattributes file after you open your project\'s Git repo in the app. To try that, click the gear icon (in the upper right corner) > Repository settings ... > Line endings and attributes. You will be asked to add the recommended .gitattributes and if you agree, the app will also perform a normalization of all the files in your repository.

Finally, the Mind the End of Your Line article provides more background and explains how Git has evolved on the matters at hand. I consider this required reading.

You\'ve probably got users in your team who use EGit or JGit (tools like Eclipse and TeamCity use them) to commit their changes. Then you\'re out of luck, as @gatinueta explained in this answer\'s comments:

This setting will not satisfy you completely if you have people working with Egit or JGit in your team, since those tools will just ignore .gitattributes and happily check in CRLF files https://bugs.eclipse.org/bugs/show_bug.cgi?id=342372

One trick might be to have them commit their changes in another client, say SourceTree. Our team back then preferred that tool to Eclipse\'s EGit for many use cases.

Who said software is easy? :-/



回答2:

Don\'t convert line endings. It\'s not the VCS\'s job to interpret data -- just store and version it. Every modern text editor can read both kinds of line endings anyway.



回答3:

You almost always want autocrlf=input unless you really know what you are doing.

Some additional context below:

It should be either core.autocrlf=true if you like DOS ending or core.autocrlf=input if you prefer unix-newlines. In both cases, your Git repository will have only LF, which is the Right Thing. The only argument for core.autocrlf=false was that automatic heuristic may incorrectly detect some binary as text and then your tile will be corrupted. So, core.safecrlf option was introduced to warn a user if a irreversable change happens. In fact, there are two possibilities of irreversable changes -- mixed line-ending in text file, in this normalization is desirable, so this warning can be ignored, or (very unlikely) that Git incorrectly detected your binary file as text. Then you need to use attributes to tell Git that this file is binary.

The above paragraph was originally pulled from a thread on gmane.org, but it has since gone down.



回答4:

Two alternative strategies to get consistent about line-endings in mixed environments (Microsoft + Linux + Mac):

A. Global per All Repositories Setup

1) Convert all to one format

find . -type f -not -path \"./.git/*\" -exec dos2unix {} \\;
git commit -a -m \'dos2unix conversion\'

2) Set core.autocrlf to input on Linux/UNIX or true on MS Windowns (repository or global)

git config --global core.autocrlf input

3) [ Optional ] set core.safecrlf to true (to stop) or warn (to sing:) to add extra guard comparing if the reversed newline transformation would result in the same file

git config --global core.safecrlf true


B. Or per Repository Setup

1) Convert all to one format

find . -type f -not -path \"./.git/*\" -exec dos2unix {} \\;
git commit -a -m \'dos2unix conversion\'

2) add .gitattributes file to your repository

echo \"* text=auto\" > .gitattributes
git add .gitattributes
git commit -m \'adding .gitattributes for unified line-ending\'

Don\'t worry about your binary files - Git should be smart enough about them.


More about safecrlf/autocrlf variables



回答5:

Try setting the core.autocrlf configuration option to true. Also have a look at the core.safecrlf option.

Actually it sounds like core.safecrlf might already be set in your repository, because (emphasis mine):

If this is not the case for the current setting of core.autocrlf, git will reject the file.

If this is the case, then you might want to check that your text editor is configured to use line endings consistently. You will likely run into problems if a text file contains a mixture of LF and CRLF line endings.

Finally, I feel that the recommendation to simply \"use what you\'re given\" and use LF terminated lines on Windows will cause more problems than it solves. Git has the above options to try to handle line endings in a sensible way, so it makes sense to use them.



回答6:

Using core.autocrlf=false stopped all the files from being marked updated as soon as I checked them out in my Visual Studio 2010 project. The other two members of the development team are also using Windows systems so a mixed environment didn\'t come into play, yet the default settings that came with the repository always marked all files as updated immediately after cloning.

I guess the bottom line is to find what CRLF setting works for your environment. Especially since in many other repositories on our Linux boxes setting autocrlf = true produces better results.

20+ years later and we\'re still dealing with line ending disparities between OSes... sad.



回答7:

These are the two options for Windows and Visual Studio users that share code with Mac or Linux users. For an extended explanation, read the gitattributes manual.

* text=auto

In your repo\'s .gitattributes file add:

*   text=auto

This will normalize all the files with LF line endings in the repo.

And depending on your operating system (core.eol setting), files in the working tree will be normalized to LF for Unix based systems or CRLF for Windows systems.

This is the configuration that Microsoft .NET repos use.

Example:

Hello\\r\\nWorld

Will be normalized in the repo always as:

Hello\\nWorld

On checkout, the working tree in Windows will be converted to:

Hello\\r\\nWorld

On checkout, the working tree in Mac will be left as:

Hello\\nWorld

Note: If your repo already contains files not normalized, git status will show these files as completely modified the next time you make any change on them, and it could be a pain for other users to merge their changes later. See refreshing a repository after changing line endings for more information.

core.autocrlf = true

If text is unspecified in the .gitattributes file, Git uses the core.autocrlf configuration variable to determine if the file should be converted.

For Windows users, git config --global core.autocrlf true is a great option because:

  • Files are normalized to LF line endings only when added to the repo. If there are files not normalized in the repo, this setting will not touch them.
  • All text files are converted to CRLF line endings in the working directory.

The problem with this approach is that:

  • If you are a Windows user with autocrlf = input, you will see a bunch of files with LF line endings. Not a hazard for the rest of the team, because your commits will still be normalized with LF line endings.
  • If you are a Windows user with core.autocrlf = false, you will see a bunch of files with LF line endings and you may introduce files with CRLF line endings into the repo.
  • Most Mac users use autocrlf = input and may get files with CRLF file endings, probably from Windows users with core.autocrlf = false.


回答8:

This is just a workaround solution:

In normal cases, use the solutions that are shipped with git. These work great in most cases. Force to LF if you share the development on Windows and Unix based systems by setting .gitattributes.

In my case there were >10 programmers developing a project in Windows. This project was checked in with CRLF and there was no option to force to LF.

Some settings were internally written on my machine without any influence on the LF format; thus some files were globally changed to LF on each small file change.

My solution:

Windows-Machines: Let everything as it is. Care about nothing, since you are a default windows \'lone wolf\' developer and you have to handle like this: \"There is no other system in the wide world, is it?\"

Unix-Machines

  1. Add following lines to a config\'s [alias] section. This command lists all changed (i.e. modified/new) files:

    lc = \"!f() { git status --porcelain \\
                 | egrep -r \\\"^(\\?| ).\\*\\\\(.[a-zA-Z])*\\\" \\
                 | cut -c 4- ; }; f \"
    
  2. Convert all those changed files into dos format:

    unix2dos $(git lc)
    
  3. Optionally ...

    1. Create a git hook for this action to automate this process

    2. Use params and include it and modify the grep function to match only particular filenames, e.g.:

      ... | egrep -r \"^(\\?| ).*\\.(txt|conf)\" | ...
      
    3. Feel free to make it even more convenient by using an additional shortcut:

      c2dos = \"!f() { unix2dos $(git lc) ; }; f \"
      

      ... and fire the converted stuff by typing

      git c2dos
      


回答9:

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:

    • https://github.com/editorconfig/
    • https://github.com/welovecoding/editorconfig-netbeans/

--- Update ---

Even if you do not want to use the above strategy, the following command is your friend (Note: on windows clients works only through git-bash and on linux clients only if compiled using --with-libpcre in ./configure).

# Print all files that have been committed with CRLF (more correctly that contain CR), so that you normalize them.
git grep -I --files-with-matches --perl-regexp \'\\r\' HEAD

One painful example:

netbeans 8.2 (on windows), will wrongly commit all text files with CRLFs on repo, 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 above command after a commit, will at least help you detect early whether your git repo has line ending issues.