Cannot get Git to properly handle CRLF issues with Eclipse startup configurations (XML files)

We have a mixed team with some people using Windows and others using Linux. We configured the IDE (Eclipse) to use LF as the line ending for source files that work well.

But we also share launch configurations. These are XML files, and Eclipse ignores the project settings for them. Instead, it always uses the platform line ending when the file is written.

To solve this problem, we have these lines in .gitattributes :

 **/* eol=lf **/*.launch text 

My understanding of this configuration is that "when Git checks any file with the .launch extension, no matter where in the tree, it converts the line ending to the default platform (no matter what they were in the Git repository") . See the docs on github :

text

This parameter tells Git to always normalize the specified files. When they are committed, they are stored with LF; during verification, they are converted to the end of lines of their own OS.

Only it does not work. I still see people committing files where each line changes; diff -R ( according to this answer ) shows that Git created the CRLF file in my Linux box.

git checkout -- server.launch doesn't change anything.

What's going on here?

Is there a way to tell Git to simply ignore any lines that end with changes in some files?

+7
git line-endings
source share
2 answers

The root cause of your problem is Eclipse. Eclipse uses the JGit library to interact with Git repositories. Unfortunately, there is an open bug ( # 342372 ) to add support for the .gitattributes file to the .gitattributes library. Therefore, although your .gitattributes settings will work when using the Git client, they are ignored by Eclipse. See this SO answer for further reading.

To test this, below is a Bash script test that will show that JGit does not use .gitattributes settings. You can download the standalone JGit script here . Ultimately, the eol attribute eol respected by the Git client and not respected by the JGit client.

 #!/bin/bash # Make sure we have all the required programs. for p in git jgit od; do [[ ! -x `which $p` ]] && { echo "Could not find executable program '$p'!" exit 1 } done # Let see what is being executed. set -x # Create a temporary Git repo. mkdir temprepo cd temprepo git init # Change core.safecrlf config so we can commit text files with non-native EOLs. git config core.safecrlf warn # Create the .gitattributes file. This file will be used in all recursive # sub-directories. A sub-directory can have its own .gitattributes file which # would override the settings in any parent directories. echo -en '* eol=lf\n*.launch text\n' >.gitattributes git add .gitattributes git commit -m 'Add .gitattributes file.' # Let create some test files with different EOLs. echo -en 'foo\rbar\r' >cr.launch echo -en 'foo\nbar\n' >lf.launch mkdir a echo -en 'foo\r\nbar\r\n' >a/crlf.launch git add cr.launch lf.launch a/crlf.launch git commit -m 'Add {cr,lf,crlf}.launch files.' # Let see what is actually stored in the Git repo. git show HEAD:cr.launch | od -A x -t x1z -w16 git show HEAD:lf.launch | od -A x -t x1z -w16 git show HEAD:a/crlf.launch | od -A x -t x1z -w16 # The commit would not have changed the working directory *.launch files. # Let inspect the file contents. od -A x -t x1z -w16 cr.launch od -A x -t x1z -w16 lf.launch od -A x -t x1z -w16 a/crlf.launch # Now let change the *.launch files in the working directory to have EOLs as # per Git settings. rm -f cr.launch lf.launch a/crlf.launch git checkout -- cr.launch lf.launch a/crlf.launch # Now let inspect the file contents again. od -A x -t x1z -w16 cr.launch od -A x -t x1z -w16 lf.launch od -A x -t x1z -w16 a/crlf.launch # Let change the EOL setting and checkout the *.launch files again to see how # they are affected. echo -en '* eol=crlf\n*.launch text\n' >.gitattributes git commit -m 'Change EOL attribute.' .gitattributes rm -f cr.launch lf.launch a/crlf.launch git checkout -- cr.launch lf.launch a/crlf.launch od -A x -t x1z -w16 cr.launch od -A x -t x1z -w16 lf.launch od -A x -t x1z -w16 a/crlf.launch # Remove the *.launch files. rm -f cr.launch lf.launch a/crlf.launch # Now, let checkout the *.launch files using JGit. Due to a bug in JGit (the # Java Git library Eclipse uses), the .gitattributes settings are ignored; # checked out *.launch files will not have CRLF EOLs. jgit reset --hard HEAD od -A x -t x1z -w16 cr.launch od -A x -t x1z -w16 lf.launch od -A x -t x1z -w16 a/crlf.launch 
+10
source share

As far as I can see, there are two problems here:

  • The file name must be .gitattributes (with leading s ).

  • The prefix **/ not understood by git. Just use *.launch to match all files in all subdirectories and /*.launch only to match files in the top level directory.

The following shell script demonstrates the correct use of the text attribute:

 #!/bin/bash set -ex rm -rf q22629396 mkdir q22629396 cd q22629396 git init echo '*.txt text' > .gitattributes git add .gitattributes git commit -m 'added .gitattributes' echo -e 'line with LF' > test.txt echo -e 'line with CRLF\r' >> test.txt echo -e 'line with LF' >> test.txt echo -e 'line with CRLF\r' >> test.txt mkdir subdir echo -e 'line with LF' > subdir/test.txt echo -e 'line with CRLF\r' >> subdir/test.txt echo -e 'line with LF' >> subdir/test.txt echo -e 'line with CRLF\r' >> subdir/test.txt git add test.txt subdir/test.txt git commit -m 'added test.txt and subdir/test.txt' git show HEAD:test.txt | hexdump -c git show HEAD:subdir/test.txt | hexdump -c 

(Tested with git version 1.7.9.5 on Ubuntu 12.04.)

Additional notes:

The text attribute only corrects line endings when checking files, and not when checking them. And eol=lf prevents automatic conversion to CRLF at checkout, and does not automatically convert CRLF to LF at checkout. Therefore, if the files have CRLFs in them in the repository, you must re-commit with LF.

If you check the file with CRLF and set the text attribute in this file, I should be marked as β€œmodified” in git status from the very beginning. Now you can run git commit in this file, which will change the line ending in the repository, but not in the working copy.

Resetting a line ending in a working copy file is then difficult. git now replaces the CRLF in the LF file before comparing with the index or repository. Because of this, git does not consider the file to be different from the perfect version and thus does nothing when you use commands such as git checkout -f . The only thing that worked in my tests was to delete the file locally and check it again: rm test.txt; git checkout -- test.txt rm test.txt; git checkout -- test.txt

+1
source share

All Articles