Git is showing me an entire file is changed, when I can't seem to figure out the changes. This is cygwin git, but it also happens in msysgit
$ git --version
git version 2.1.1
$ diff <(git show HEAD:File.cs) <(cat File.cs)
// Shows no differences
$ diff <(git show HEAD:File.cs | xxd) <(xxd File.cs)
// Shows no differences
$ git diff
// shows the entire file has changed
$ git hash-object <(git show HEAD:File.cs)
7b3762473342a5b040835bfef9f6b45c109ba48b
$ git hash-object <(cat File.cs)
7b3762473342a5b040835bfef9f6b45c109ba48b
$ git hash-object File.cs
7b3762473342a5b040835bfef9f6b45c109ba48b
I have
$ git config --get core.fileMode
false
and
$ git config --get core.autocrlf
true
I truly have no idea what's going on, everything wants them to be the same, yet git wants to create a commit saying the entire contents was deleted and recreated. Does anyone who knows git plumbing better have a suggestion?. All I can think of is git show is removing/normalizing odd line endings.
UPDATE:
I'm pretty sure its happening because development process is like this. Checkout from git, rsync to dev machine, develop, rsync back. I believe rsync is messing with the line endings some. It's just weird that gits not reporting about the line endings, and it seems to get really confused about what the hell is happening. Even though diffing the binary representation of the files seem to be identical.
UPDATE 2:
So this is super annoying, and I feel like I have stumbled upon a bug in git.
For instance
$ git gc
$ git checkout -- .
$ git clean -fd
$ git status
> shows a heap of modified files
I'm pretty sure that should show no changes, no matter where its run, but I get a list of 20 odd things :(
These changes mean that metadata about your file changed, however the content of your file did not. If you're working in a group, this may start to intefere with pushes or just add noise to your commits.
There are two Git commands a developer must use in order to discard all local changes in Git, remove all uncommited changes and revert their Git working tree back to the state it was in when the last commit took place. The commands to discard all local changes in Git are: git reset –hard. git clean -fxd.
autocrlf . This is a similar approach to the attributes mechanism: the idea is that a Windows user will set a Git configuration option core. autocrlf=true and their line endings will be converted to Unix style line endings when they add files to the repository.
You can run the git diff HEAD command to compare the both staged and unstaged changes with your last commit. You can also run the git diff <branch_name1> <branch_name2> command to compare the changes from the first branch with changes from the second branch. Order does matter when you're comparing branches.
This can be caused by a .gitattributes
file indicating to git that it should do EOL normalization but the repository containing non-normalized line endings.
The simple fix is to remove the relevant line from .gitattributes
. This could be
* text=auto
or
*.cs text
A quick example of how this could happen goes like this:
$ echo "Hello World" > example.txt
$ unix2dos example.txt #Make sure it uses CRLF
$ git add example.txt
$ git commit -m "commit 1"
$ #Instruct git that all .txt files should be normalized
$ echo '*.txt text' >> .gitattributes
$ git add .gitattributes
$ git commit -m "commit 2"
Now the repository is in a strange state, because .gitattributes
claims the file should be normalized before adding it to the index, but the current committed version is not normalized.
However, at this point, git status
doesn't notice that, because the file itself has not changed in size or mtime since it was added to the index, so the index is considered to be up to date:
$ git status
On branch master
nothing to commit, working directory clean
But anything which invalidates the index will cause git to consider the file to be dirty:
$ touch example.txt
On branch master
Changes not staged for commit:
modified: example.txt
no changes added to commit (use "git add" and/or "git commit -a")
And git reset --hard
or any other action to try to reset the file to the state it's supposed to be in will not fix this. This is because there is no way to add the file to the index in it's current state as it is in the repository, because git has been instructed to normalize that file, and that normalization cannot ever produce the object as it currently is committed.
This is why the GITATTRIBUTES(1)
man page recommends to explicitly invalidate the entire index when introducing line-ending normalization like so:
$ echo "* text=auto" >>.gitattributes
$ rm .git/index # Remove the index to force Git to
$ git reset # re-scan the working directory
$ git status # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
Read the section on "End-of-line conversion" in the gitattributes man page for more details.
Instead of going with the quick fix of just removing that line from .gitattributes
, you may want to instead keep the line ending normalization rules and go ahead and normalize them now. That basically just means committing the 20+ changes that won't go away, but you can do so methodically by following the above instructions about introducing line ending normalization (minus editing the .gitattributes
), and then feeling confident that it won't happen again, because all the files are now committed with normalized endings, and any future files you add will also be normalized. It's personal preference, mostly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With