Search code examples
gitcross-platformnewlinegitattributescore.autocrlf

git add --renormalize does not re-checkout my files with the correct line endings


I have a repository which I use between Windows and Linux.

Currently some files, for example the file myfolder/myfile.txt is stored with CRLF (DOS) line endings and checked out with CRLF linedendigs.

On my current machine (Linux) I want all text files to always be checked out as LF (Linux) line endings. For this I have done the following:

  1. I made sure git config --get core.autocrlf outputs true. (Nothing is set in this repo; it is the global value.)

  2. I created a .gitattributes file with the following content:

    # Set the default behavior
    * text=auto
    
  3. I ran

     git add --renormalize .
    

Then I checked with

git status

and it told me:

On branch main
Your branch is up to date with 'origin/main'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitattributes

nothing added to commit but untracked files present (use "git add" to track)

Also the file myfolder/myfile.txt has still CRLF line endings.

What goes wrong here? I want all text files to be checked out as LF line endings and how I understand the documentation the --renormalize option is doing exactly that. - But not in my case.


Solution

  • TLDR:

    These configurations should work for you on Linux and Windows (unless you are working with Windows-specific technology):

    git config --global core.autocrlf false
    git config --global core.eol lf
    

    Once, you've done that, you then need to make Git perform a checkout of the file that should have LF in your working directory. One way to do that is to remove it from the working directory and then perform a checkout:

    rm myfolder/myfile.txt
    git checkout HEAD -- myfolder/myfile.txt
    

    If you have core.autocrlf = true and your file has the text attribute set (directly or via the text=auto without having set the eol attribute specified), you will always get CRLF for that file in your working directory when you perform a checkout.

    This makes sense in terms of the name "autocrlf" since it's there to perform automatic CRLF conversion at checkout for Windows developers, but it also makes sure to convert any new files to LF at checkin to avoid Windows devs introducing LF in the repo.

    Your current configuration for performing a checkout of a text files is marked in red in the following diagram.

    enter image description here

    Based on the information you've provided, I'm going to assume that the line endings for myfolder/myfile.txt inside the git repo is already LF, which would explain why you don't see any changes when you do git status.

    Now, if you want to fix this and checkout the file as LF, you could simply switch autocrlf to false:

    git config --global core.autocrlf false

    That would put you in the situation in green:

    enter image description here

    And regarding the value of core.eol, you have two main options:

    1. Leave it unspecified which is the equivalent of having git config --global core.eol native

    Or (even better in my opinion):

    1. git config --global core.eol lf

    If you choose option 2, all files stored with LF in the repo will keep their LF at checkout even when you boot on Windows. Considering all modern Windows programs can deal with LF, it shouldn't be a problem and you won't face any issues with CRLF causing problems in you docker containers.

    If you are working with Windows-specific technologies, you can always add specific entries to your .gitattributes file to avoid having LF Windows-specific extensions.

    For example:

    # INI file extension
    *.[iI][nN][iI]              text eol=crlf
    
    # Batch scripts (cmd, bat)
    *.[cC][mM][dD]              text eol=crlf
    *.[bB][aA][tT]              text eol=crlf
    

    Final step

    Once, you've done all that. You then need to make Git perform a checkout of the file(s) that should have LF in your working directory. One way to do that is to remove it from the working directory and then perform a checkout:

    rm myfolder/myfile.txt
    git checkout HEAD -- myfolder/myfile.txt
    

    Another way to do that is to remove it from the working directory (and the index) and then perform a reset:

    git rm myfolder/myfile.txt
    git reset --hard
    

    The diagram used in this answer was inspired greatly from this answer with some improvements based on a careful read of the documentation and some PowerShell script to explore different scenarios. Full version available here.

    See also the article git's autocrlf=true considered harmful | markentier.tech


    Diagram updates:

    • By including the eol attribute in the checkout part of the diagram, it makes it more complete, since eol specified in the .gitattributes file has precedence over core.autocrlf.