Unstaged Changes Left After Git Reset --Hard

Unstaged Changes Left After Git Reset --Hard

After git reset --hard, git status gives me files within the Changes not staged for commit: section.

I've also tried git reset ., git checkout -- . and git checkout-index -f -a, to no avail.

So, how can I get rid of those unstaged changes?

This seems to hit only Visual Studio project files. Weird. See this paste: . What is special with those files, is that in .gitattributes I have:

*.sln        eol=crlf
*.vcproj     eol=crlf
*.vcxproj*   eol=crlf

Also, autocrlf is set to false in my global .gitconfig. Could that be somehow relevant?

8

21 Answers

I had the same problem and it was related to the .gitattributes file. However the file type that caused the problem was not specified in the .gitattributes.

I was able to solve the issue by simply running

git rm .gitattributes
git add -A
git reset --hard
13

I have resolved this problem using following steps

  1. Remove every file from Git's index.

    git rm --cached -r .
    
  2. Rewrite the Git index to pick up all the new line endings.

    git reset --hard
    

Solution was part of steps described on Configuring Git to handle line endings

10

Git won't reset files that aren't on repository. So, you can:

$ git add .
$ git reset --hard

This will stage all changes, which will cause Git to be aware of those files, and then reset them.

If this does not work, you can try to stash and drop your changes:

$ git stash
$ git stash drop
7

If you use Git for Windows, this is likely your issue

I've had the same problem and stash, hard reset, clean or even all of them was still leaving changes behind. What turned out to be the problem was the x file mode that was not set properly by git. This is a "known issue" with git for windows. The local changes show in gitk and git status as old mode 100755 new mode 100644, without any actual file differences.

The fix is to ignore the file mode:

git config core.filemode false

More info here

7

Okay, I've kind of solved the problem.

It seemed that the .gitattributes file, containing:

*.sln        eol=crlf
*.vcproj     eol=crlf
*.vcxproj*   eol=crlf

made the project files appear unstaged. I am clueless why that is, and I'm really hoping that someone privy to the ways of git will give us a nice explanation.

My fix was to remove these files, and to add autocrlf = false under [core] in .git/config.

This does not amount to exactly the same thing as the previous configuration, as it requires every dev to have autocrlf = false. I'd like to find a better fix.

EDIT:

I commented the incriminating lines, uncommented them and it worked. What the ... I don't even ... !

5

Possible Cause #1 - Line Ending Normalization

One situation in which this can happen is when the file in question was checked into the repository without the correct configuration for line endings (1) resulting in a file in the repository with either the incorrect line endings, or mixed line endings. To confirm, verify that git diff shows only changes in line endings (these may not be visible by default, try git diff | cat -v to see carriage returns as literal ^M characters).

Subsequently, someone probably added a .gitattributes or modified the core.autocrlf setting to normalize line endings (2). Based on the .gitattributes or global config, Git has applied local changes to your working copy that apply the line ending normalization requested. Unfortunately, for some reason git reset --hard does not undo these line normalization changes.

Solution

Workarounds in which the local line endings are reset will not solve the problem. Every time the file is "seen" by git, it will try and reapply the normalization, resulting in the same issue.

The best option is to let git apply the normalization it wants to by normalizing all the line endings in the repo to match the .gitattributes, and committing those changes -- see Trying to fix line-endings with git filter-branch, but having no luck.

If you really want to try and revert the changes to the file manually then the easiest solution seems to be to erase the modified files, and then to tell git to restore them, although I note this solution does not seem to work consistently 100% of the time (WARNING: DO NOT run this if your modified files have changes other than line endings!!):

    git status --porcelain | grep "^ M" | cut -c4- | xargs rm
    git checkout -- .

Note that, unless you do normalize the line endings in the repository at some point, you will keep running into this issue.

Possible Cause #2 - Case Insensitivity

The second possible cause is case insensitivity on Windows or Mac OS/X. For example, say a path like the following exists in the repository:

/foo/bar

Now someone on Linux commits files into /foo/Bar (probably due to a build tool or something that created that directory) and pushes. On Linux, this is actually now two separate directories:

/foo/bar/fileA
/foo/Bar/fileA

Checking this repo out on Windows or Mac may result in modified fileA that cannot be reset, because on each reset, git on Windows checks out /foo/bar/fileA, and then because Windows is case insensitive, overwrites the content of fileA with /foo/Bar/fileA, resulting in them being "modified".

Another case may be an individual file(s) that exists in the repo, which when checked out on a case insensitive filesystem, would overlap. For example:

/foo/bar/fileA
/foo/bar/filea

There may be other similar situations that could cause such problems.

git on case insensitive filesystems should really detect this situation and show a useful warning message, but it currently does not (this may change in the future -- see this discussion and related proposed patches on the git.git mailing list).

Robert Thorne
Author

Robert Thorne

Robert Thorne covers electric vehicle innovations, autonomous driving systems, global mobility trends, and automotive engineering developments.