Re: Git apply can convert LF file into CRLF when .gitattributes file is a part of a patch
From: Torsten =?unknown-8bit?Q?B=C3=B6gershausen?= <hidden>
Date: 2021-09-11 06:46:34
On Wed, Sep 08, 2021 at 12:53:42AM +0000, Mirochnik, Oleg V wrote:
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.
It was probablty me who suggested to report this issue here on the mailing list. Thanks for doing so. I extracted your test script, run it on a Mac, and it seems to give a different result then your run. Just to quote the las lines:
+++ patch no CRHEAD is now at a47b66d init
+++ After reset and before patchLF cr/foo LF lf/foo LF lf/.gitattributes
+++ After patchLF cr/foo LF lf/foo LF lf/.gitattributes --------- Seeing this, I am unsure what is going on. It may be an idea to convert the script into a real git test case, and send it to the list. There is a command git ls-files --eol to let Git report the line endings of files Using ---------------- echo "this is what I expected" >expect && git ls-files --eol >actual && test_cmp expect actual ------------------ would allow everybody to see what is possible wrong. And somebody may be willing to dig deeper - and if it a bug, send a patch
quoted hunk ↗ jump to hunk
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 diffCR cr/foo LF lf/foo LF lf/.gitattributes+++ PatchesCR patch.lf-only CR patch.with CR patch.without Cloning into '3'... done.+++ patch w/o .gitattributesHEAD is now at fc793f1 init+++ After reset and before patchCR cr/foo LF lf/foo LF lf/.gitattributes+++ After patchCR cr/foo LF lf/foo LF lf/.gitattributes+++ patch with .gitattributesHEAD is now at fc793f1 init+++ After reset and before patchCR cr/foo LF lf/foo LF lf/.gitattributes+++ After patchCR cr/foo CR lf/foo CR lf/.gitattributes+++ patch no CRHEAD is now at fc793f1 init+++ After reset and before patchCR cr/foo LF lf/foo LF lf/.gitattributes+++ After patchCR cr/foo LF lf/foo LF lf/.gitattributes