git filter not 'unmodifying' file

529 views Asked by At

I am working with an IDE which produces a version in some generated, but strongly required files of libraries. So there is an issue if I want to use the library with multiple versions or I see a load of changes which are in fact senseless.

Summary: I want to ignore a single line of one or multiple files which I thought git's filters are the right approach. I am able to grep for the relevant line without a problem as one might see reading further.

Long story short, I set up a git filter to revert any modification to the version in the header file. (Please note that there might be different modifications which are relevant in this file.)

[filter "ignore-version"]
    smudge = cat %f || cat
    clean  = git ls-files %f --error-unmatch >&- 2>&- \
              && sed \"/version/c $(git show HEAD:%f | grep version)\" || cat

(I added escaped line breaking for better reading and changed the word to match for simplicity. In the original version there are no collisions possible.)

  1. git ls-files checks if the file is already in the repository (currently HEAD)

1.1 if present, sed will do the dirty work to replace the whole line with the already tracked one

1.2 if not, cat will do nothing but go ahead (this should ensure a not yet tracked file will not get lost)

So far, it works. (I can live with the fact that the filter silently converts all CRLF to LF...)

Problem: The fixed file is marked as modified by git, although the most recent file of the repository and the filtered version are binary equal. I checked this using kdiff as separate tool.


Edit 1: Here is some output which shows the equality of the two file versions:

$ git show HEAD:file.txt | md5sum
9f95c28cebe4f45b8efb7b0ae64dfa56
$ cat file.txt | md5sum
894e7d1b28180b7a193bf3cdd6ceaacb
$ cat file.txt | git ls-files file.txt --error-unmatch >&- 2>&- \
              && sed \"/version/c $(git show HEAD:file.txt | grep version)\" 
              || cat | md5sum
9f95c28cebe4f45b8efb7b0ae64dfa56

Edit 2: Additionally, the output of the difference...

$ git diff file.txt
warning: LF will be replaced by CRLF in file.txt.
The file will have its original line endings in your working directory.

Please note that the checked in version of this file contains only LF as by the previous commit. Note also that the setting core.autocrlf is true without having anything but the filter specification in the .gitattributes file.

1

There are 1 answers

0
maxik On BEST ANSWER

Finally, I solved it. The file of question was in a strange state, it seems like the checked out version had unix style line endings which is not right regarding the git configuration (check out windows style, commit unix style). After staging this particular file it was instantly removed from staging area without any mention and is now considered unchanged. So I think git cleaned the working directory file during staging (line endings) and now it works.

Sorry for the noise.


Steps to completly check the problem:

git init
echo "version=0.1" > file.txt
echo "*.txt filter=ignore-version" > .gitattributes
git config --local filter.ignore-version.clean 'git ls-files %f --error-unmatch >&- 2>&- \
    && sed -b "/version/c $(git show HEAD:%f | grep version)" || cat'
git config --local filter.ignore-version.smudge 'cat %f || cat'
git add file.txt .gitattributes
git commit -m "initial commit"
# -----
echo "version=0.2" > file.txt
git status

Status should not report any changes. It worked for me using bare repositories on both, Linux and Windows.