Is VIM adding the Windows newlines?

9,359

Solution 1

Vim will detect the original fileformat (among those configured in 'fileformats'), and write with the same one. The only way for Vim to switch (e.g. from Unix to Windows-style) is via an explicit :setlocal fileformat=dos. It's unlikely that you have that in your config; :verbose setl ff? could tell you.

I wouldn't be too concerned about the Git diff ifself (as long as not all lines appear as changed, then you really have a switch of line endings), but rather that what gets committed is alright.

Note that with the Git setting autocrlf = true, Git will convert newlines to the system's standard when checking out files, and to LF newlines when committing. So everything might be just fine, only the Git diff output is confusing you.

Solution 2

This is evidence that we are all living in the Matrix. If this were really the 21'st century, then we would not still be fighting with different line endings.

Vim does a pretty good job of doing The Right Thing with line endings. The details are explained under :help 'ffs'. Of course, vim cannot read your mind: if your file has inconsistent line endings, then vim may not do what you want.

I suggest opening the file in vim and then

:e! ++ff=unix

This will reload the file from disk, forcing vim to use unix-style line endings. Then you should see exactly which lines, any, have CRLF endings, because they will end with raw ^M characters.

While I love git, I do not know and trust it as well as I do vim. I think that some people recommend "set it and forget it" configurations for git's crlf settings that can lead to confusion. I prefer to avoid the setting that @Ingo Karkat mentioned in his answer. I want git to check out the same file that was checked in, and let me (and vim) take care of the line endings.

Solution 3

git diff only shows carriage returns (^M) in added lines, but not in removed or unchanged lines. You can see this, if you use the -R flag, which shows the diff the other way around.

$ git diff -R:

-   IP_ADDR: 'http://2.4.6.8:143'
+   IP_ADDR: 'http://1.2.3.4:143'^M

So vim is not adding anything; especialy not for only one line. Vim uses the lineendings it finds in the file while opening it.

Solution 4

Vim is based on the value of the fileformat option to determine whether the currently opened file is dos or unix, or a mac file.The value of the fileformat option is determined by the value of the fileformats option.

When vim opens a file, vim will determine a valid fileformat option value for the current buffer based on the value of the current fileformats option. The following is description of the vim manual about how vim determines the value of the fileformat option of the current buffer by the value of the fileformats option:

'fileformats' 'ffs' string (default:
                Vim+Vi  MS-DOS, MS-Windows OS/2: "dos,unix",
                Vim Unix: "unix,dos",
                Vim Mac: "mac,unix,dos",
                Vi  Cygwin: "unix,dos",
                Vi  others: "")
            global
            {not in Vi}
    This gives the end-of-line (<EOL>) formats that will be tried when
    starting to edit a new buffer and when reading a file into an existing
    buffer:
    - When empty, the format defined with 'fileformat' will be used
      always.  It is not set automatically.
    - When set to one name, that format will be used whenever a new buffer
      is opened.  'fileformat' is set accordingly for that buffer.  The
      'fileformats' name will be used when a file is read into an existing
      buffer, no matter what 'fileformat' for that buffer is set to.
    - When more than one name is present, separated by commas, automatic
      <EOL> detection will be done when reading a file.  When starting to
      edit a file, a check is done for the <EOL>:
      1. If all lines end in <CR><NL>, and 'fileformats' includes "dos",
         'fileformat' is set to "dos".
      2. If a <NL> is found and 'fileformats' includes "unix", 'fileformat'
         is set to "unix".  Note that when a <NL> is found without a
         preceding <CR>, "unix" is preferred over "dos".
      3. If 'fileformat' has not yet been set, and if a <CR> is found, and
         if 'fileformats' includes "mac", 'fileformat' is set to "mac".
         This means that "mac" is only chosen when:
          "unix" is not present or no <NL> is found in the file, and
          "dos" is not present or no <CR><NL> is found in the file.
         Except: if "unix" was chosen, but there is a <CR> before
         the first <NL>, and there appear to be more <CR>s than <NL>s in
         the first few lines, "mac" is used.
      4. If 'fileformat' is still not set, the first name from
         'fileformats' is used.
      When reading a file into an existing buffer, the same is done, but
      this happens like 'fileformat' has been set appropriately for that
      file only, the option is not changed.
    When 'binary' is set, the value of 'fileformats' is not used.

    When Vim starts up with an empty buffer the first item is used.  You
    can overrule this by setting 'fileformat' in your .vimrc.

    For systems with a Dos-like <EOL> (<CR><NL>), when reading files that
    are ":source"ed and for vimrc files, automatic <EOL> detection may be
    done:
    - When 'fileformats' is empty, there is no automatic detection.  Dos
      format will be used.
    - When 'fileformats' is set to one or more names, automatic detection
      is done.  This is based on the first <NL> in the file: If there is a
      <CR> in front of it, Dos format is used, otherwise Unix format is
      used.
    Also see |file-formats|.
    For backwards compatibility: When this option is set to an empty
    string or one format (no comma is included), 'textauto' is reset,
    otherwise 'textauto' is set.
    NOTE: This option is set to the Vi default value when 'compatible' is
    set and to the Vim default value when 'compatible' is reset.

Going back to your question, your file is identified as a dos file in vim, so when you save the file and exit vim, vim will automatically replace the newline character with the dos style newline: .

In your git work directory tree, this file is a dos file, but since this file is a unix file in the git index tree , so, by using git diff ,you will see that the file has changed. For a file in Unix format, the extra will be displayed as ^M character.

Share:
9,359

Related videos on Youtube

dotancohen
Author by

dotancohen

Updated on September 18, 2022

Comments

  • dotancohen
    dotancohen over 1 year

    Notice the line endings from git diff:

    -   IP_ADDR: 'http://1.2.3.4:143'
    +   IP_ADDR: 'http://2.4.6.8:143'^M
    

    I edited this file by putting the cursor on 1 then pressing ct: and then entering the new IP address. No complete lines were added or removed from the file. I do notice though that the file shows as type dos in VIM.

    Why would VIM change the line ending if I didn't explicitly edit that part of the document? Also, seeing how diff shows that there was no ^M in the original line, how else might VIM have decided that this is a dos file?