问题
I have a repo that has two files that supposedly I changed locally.
So I'm stuck with this:
$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: dir1/foo.aspx
# modified: dir2/foo.aspx
#
no changes added to commit (use "git add" and/or "git commit -a")
Doing git diff
says that the entire file contents have changed, even though from eyeballing it that seems untrue (there seem to be common line ranges that diff seems to be failing to see).
Interestingly I don't remember changing these files locally. This repo is used with one remote repo (private, at GitHub.com, FWIW).
No matter what I've tried, I can't discard these local changes. I have tried all of:
$ git checkout -- .
$ git checkout -f
$ git checkout -- dir1/checkout_receipt.aspx
$ git reset --hard HEAD
$ git stash save --keep-index && git stash drop
$ git checkout-index -a -f
In other words I've tried everything described in How do I discard unstaged changes in Git? plus more. But the 2 files remain stuck as "changed but not committed".
What the heck would cause two files to be stuck like this and seemingly "un-revert-table"??
P.S. In the list above showing commands I'd already tried, I mistakenly wrote git revert
when I meant git checkout
. I'm sorry and thank you to those of you who answered that I should try checkout
. I edited the question to correct it. I definitely did already try checkout
.
回答1:
What are the line endings in the files? I'm betting they're CRLF. If they are, check out this guide: http://help.github.com/line-endings/
In short, you need to make sure git is set to convert the line endings to LF on commit, and then commit those files. Files in the repo should always be LF, files checked out should be the OS's native, assuming you set git correctly.
回答2:
I spent hours trying to solve a similar issue - a remote branch that I had checked out, which stubbornly showed four files as 'Changed but not updated', even when deleting all files and running git checkout -f
again (or other variations from this post)!
These four files were necessary, but certainly hadn't been modified by me. My final solution - persuade Git that they had not been changed. The following works for all checked out files, showing 'modified' status - make sure you have already committed/stashed any that have really been modified!:
git ls-files -m | xargs -i git update-index --assume-unchanged "{}"
On Mac OSX, however xargs operates a little bit different (thx Daniel for the comment):
git ls-files -m | xargs -I {} git update-index --assume-unchanged {}
I've added this as a placeholder for myself for next time, but I hope it helps someone else too.
-Al
回答3:
this is how I fixed the same problem in my case: open .gitattributes change:
* text=auto
to:
#* text=auto
save and close , then revert or reset, thanks to @Simon East for the hint
回答4:
Another possibility is that the difference (that's preventing your from reverting these files with a checkout command) is one of file mode. This is what happened to me. On my version of git you can discover this by using
git diff dir1/foo.aspx
And it will show you file mode changes. It still won't let you revert them, though. For that use either
git config core.filemode false
or change your git .config in your text editor by adding
[core]
filemode = false
After you do this, you can use
git reset HEAD dir1/foo.aspx
and the file should disappear.
(I got all of this from the answer to How do I make git ignore mode changes (chmod)?)
回答5:
Try to revert local changes:
git checkout -- dir1/foo.aspx
git checkout -- dir2/foo.aspx
回答6:
I had some phantom changed files that were showing as modified, but were actually identical.
Running this command sometimes works:
(Turns off git's "smart" but often unhelpful line-ending conversions)
git config --local core.autocrlf false
But in another case I found it was due to a .gitattributes
file in the root which had some line-ending settings present, which was trying to apply autocrlf
for certain files even when it was turned off. That wasn't actually helpful, so I deleted .gitattributes
, committed, and the file no longer showed as modified.
回答7:
git checkout dir1/foo.aspx
git checkout dir2/foo.aspx
回答8:
For me the issue was not about line endings. It was about changing case in folder name (Reset_password -> Reset_Password). This solution helped me: https://stackoverflow.com/a/34919019/1328513
回答9:
You also might have had a problem related to directories naming letter cases. Some of your colleagues could have changed the name of the directory from e.g. myHandler to MyHandler. If you later on pushed and pulled some of the files of the original directory you would have had 2 separate directories on the remote repository AND only one on your local machine since on Windows you only can have just one. And you're in trouble.
To check if that is the case, just see if the remote repository has double structure.
To fix this, make a backup copy of the parent directory outside of the repo, then delete the parent directory, push it. Make a pull (here's when the second one marked as deleted should appear on status) and push again. After that, recreate the whole structure from your backup and push the changes again.
回答10:
I think it would be helpful to provide a hint on how to reproduce the issue, in order to better understand the problem:
$ git init
$ echo "*.txt -text" > .gitattributes
$ echo -e "hello\r\nworld" > 1.txt
$ git add 1.txt
$ git commit -m "committed as binary"
$ echo "*.txt text" > .gitattributes
$ echo "change.." >> 1.txt
# Ok let's revert now
$ git checkout -- 1.txt
$ git status
modified: 1.txt
# Oooops, it didn't revert!!
# hm let's diff:
$ git diff
warning: CRLF will be replaced by LF in 1.txt.
The file will have its original line endings in your working
directory.
diff --git a/1.txt b/1.txt
index c78c505..94954ab 100644
--- a/1.txt
+++ b/1.txt
@@ -1,2 +1,2 @@
-hello
+hello
world
# No actual changes. Ahh, let's change the line endings...
$ file 1.txt
1.txt: ASCII text, with CRLF line terminators
$ dos2unix 1.txt
dos2unix: converting file 1.txt to Unix format ...
$ git diff
git diff 1.txt
diff --git a/1.txt b/1.txt
index c78c505..94954ab 100644
--- a/1.txt
+++ b/1.txt
@@ -1,2 +1,2 @@
-hello
+hello
world
# No, it didn't work, file is still considered modified.
# Let's try to revert for once more:
$ git checkout -- 1.txt
$ git status
modified: 1.txt
# Nothing. Let's use a magic command that prints wrongly committed files.
$ git grep -I --files-with-matches --perl-regexp '\r' HEAD
HEAD:1.txt
2nd way to reproduce:
In the above script replace this line:echo "*.txt -text" > .gitattributes
withgit config core.autocrlf=false
and keep the rest of the lines as is
What all the above say? A text file can (under some circumstances) be
committed with CRLF, (e.g. -text
in .gitattributes
/ or core.autocrlf=false
).
When we later want to treat the same file as text (-text
-> text
) it will need to be committed again.
Of course you can temporarily revert it (as correctly answered by Abu Assar). In our case:
echo "*.txt -text" > .gitattributes
git checkout -- 1.txt
echo "*.txt text" > .gitattributes
The answer is: do you really want to do that, because it's gonna cause the same problem everytime you change the file.
For the record:
To check which files can cause this problem in your repo execute the following command (git should be compiled with --with-libpcre):
git grep -I --files-with-matches --perl-regexp '\r' HEAD
By committing the file(s) (supposing that you want to treat them as text), it is the same thing as doing what is proposed in this link http://help.github.com/line-endings/ for fixing such problems. But, instead of you removing .git/index
and performing reset
, you can just change the file(s), then perform git checkout -- xyz zyf
and then commit.
来源:https://stackoverflow.com/questions/6335521/git-how-to-revert-2-files-that-are-stubbornly-stuck-at-changed-but-not-committ