git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Git apply can convert LF file into CRLF when .gitattributes file is a part of a patch

From
MVMirochnik, Oleg V <oleg.v.mirochnik@intel.com>
Date
Sep 8, 2021, 00:53 UTC
Message-ID
<SJ0PR11MB49429B90AA71A06BD4A3BD15C6D49@SJ0PR11MB4942.namprd11.prod.outlook.com>
Hi,

Originally the issue was reported in https://github.com/git-for-windows/git/issues/3409 But I was asked to report it in the mail list as the issue is not a Windows related.

As you can see below "git apply --binary" converts files into CRLF mode if .gitattributes file modification is included into a patch file. IMO behavior should be consistent - "git apply --binary" should not convert files into CRLF mode because of unrelated change in .gitattributes file.

Steps: $ cat doit git --version --build-options git config --global core.autocrlf true

rm -rf tst mkdir tst cd tst mkdir repo.git cd repo.git git init --bare cd .. git clone repo.git 1 cd 1 mkdir cr lf echo '* -text' > lf/.gitattributes for d in *; do for b in {1..5}; do echo foo >> $d/foo; done; done git add * git commit -m init git push cd ../

git clone repo.git/ 2 cd 2 for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done for a in `find * -type f`; do echo '# dummy' >> $a; done git commit -a -m dummy echo "" echo +++ After commit and before diff for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done git diff --binary HEAD~ -- cr lf > ../patch.with git diff --binary HEAD~ -- cr lf/foo > ../patch.without git diff --binary HEAD~ -- lf > ../patch.lf-only cd ..

echo "" echo +++ Patches for a in patch*; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done

git clone repo.git 3 cd 3

echo "" echo +++ patch w/o .gitattributes git reset --hard echo +++ After reset and before patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done git apply --binary ../patch.without echo +++ After patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done

echo "" echo +++ patch with .gitattributes git reset --hard echo +++ After reset and before patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done git apply --binary ../patch.with echo +++ After patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done

echo "" echo +++ patch no CR git reset --hard echo +++ After reset and before patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done git apply --binary ../patch.lf-only echo +++ After patch for a in `find * -type f`; do echo `od -c $a | grep -q '\\r' && echo CR || echo LF` $a; done

git config --global core.autocrlf false
$ sh doit
git version 2.29.2
cpu: x86_64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
Initialized empty Git repository in /tmp/issue3409/tst/repo.git/
Cloning into '1'...
warning: You appear to have cloned an empty repository.
done.
warning: LF will be replaced by CRLF in cr/foo.
The file will have its original line endings in your working directory
[master (root-commit) fc793f1] init
 3 files changed, 11 insertions(+)
 create mode 100644 cr/foo
 create mode 100644 lf/.gitattributes
 create mode 100644 lf/foo
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 24 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 378 bytes | 378.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
To /tmp/issue3409/tst/repo.git
 * [new branch]      master -> master
Cloning into '2'...
done.
CR cr/foo
LF lf/foo
LF lf/.gitattributes
warning: LF will be replaced by CRLF in cr/foo.
The file will have its original line endings in your working directory
[master 718534d] dummy
 3 files changed, 3 insertions(+)

+++ After commit and before diff CR cr/foo LF lf/foo LF lf/.gitattributes

+++ Patches CR patch.lf-only CR patch.with CR patch.without Cloning into '3'... done.

+++ patch w/o .gitattributes HEAD is now at fc793f1 init +++ After reset and before patch CR cr/foo LF lf/foo LF lf/.gitattributes +++ After patch CR cr/foo LF lf/foo LF lf/.gitattributes

+++ patch with .gitattributes HEAD is now at fc793f1 init +++ After reset and before patch CR cr/foo LF lf/foo LF lf/.gitattributes +++ After patch CR cr/foo CR lf/foo CR lf/.gitattributes

+++ patch no CR HEAD is now at fc793f1 init +++ After reset and before patch CR cr/foo LF lf/foo LF lf/.gitattributes +++ After patch CR cr/foo LF lf/foo LF lf/.gitattributes

Next: Torsten B��gershausen
Message 1 of 2 in “Git apply can convert LF file into CRLF when .gitattributes file is a part of a patch”
  1. Mirochnik, Oleg VSep 8, 2021
  2. Torsten B��gershausenSep 11, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.