Git状态显示修改,但使用git checkout -- <file>命令无法删除它们。

260

我想要删除我的工作副本中的所有更改。
运行git status会显示已修改的文件。
无论我做什么都不能删除这些修改。
例如:

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ 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:   Rhino.Etl.Core/Enumerables/CachingEnumerable.cs
#       modified:   Rhino.Etl.Core/Pipelines/SingleThreadedPipelineExecuter.cs
#       modified:   Rhino.Etl.Tests/Rhino.Etl.Tests.csproj
#       modified:   Rhino.Etl.Tests/SingleThreadedPipelineExecuterTest.cs
#
no changes added to commit (use "git add" and/or "git commit -a")

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ git checkout -- Rhino.Etl.Core/Enumerables/CachingEnumerable.cs

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ 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:   Rhino.Etl.Core/Enumerables/CachingEnumerable.cs
#       modified:   Rhino.Etl.Core/Pipelines/SingleThreadedPipelineExecuter.cs
#       modified:   Rhino.Etl.Tests/Rhino.Etl.Tests.csproj
#       modified:   Rhino.Etl.Tests/SingleThreadedPipelineExecuterTest.cs
#
no changes added to commit (use "git add" and/or "git commit -a")

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ git checkout `git ls-files -m`

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ 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:   Rhino.Etl.Core/Enumerables/CachingEnumerable.cs
#       modified:   Rhino.Etl.Core/Pipelines/SingleThreadedPipelineExecuter.cs
#       modified:   Rhino.Etl.Tests/Rhino.Etl.Tests.csproj
#       modified:   Rhino.Etl.Tests/SingleThreadedPipelineExecuterTest.cs
#
no changes added to commit (use "git add" and/or "git commit -a")

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ git reset --hard HEAD
HEAD is now at 6c857e7 boo libraries updated to 2.0.9.2 and rhino.dsl.dll updated.

rbellamy@PROMETHEUS /d/Development/rhino-etl (master)
$ 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:   Rhino.Etl.Core/Enumerables/CachingEnumerable.cs
#       modified:   Rhino.Etl.Core/Pipelines/SingleThreadedPipelineExecuter.cs
#       modified:   Rhino.Etl.Tests/Rhino.Etl.Tests.csproj
#       modified:   Rhino.Etl.Tests/SingleThreadedPipelineExecuterTest.cs
#
no changes added to commit (use "git add" and/or "git commit -a")

6
不确定为什么 git reset --hard 在这里没起作用。注意:应该使用 git checkout -- \git ls-files -m` 命令来取消文件(--`)。 - VonC
2
如果您删除了文件并使用 checkout -- <file>,它应该可以工作。在某些情况下(包括存在 CRLF 不匹配的情况),更改检测可能有点挑剔。 - eckes
可能是无法在Git中放弃更改的重复问题。 - BuZZ-dEE
1
@BuZZ-dEE - 这是一个重复的问题,而且旧的问题会优先考虑。但是,虽然您链接到的问题本质上是相同的,但我下面接受的答案比那里的任何答案都更具信息量,并解决了我的问题。 - rbellamy
“git update-index --assume-unchaged” 是一种针对无聊情况的多功能工具,它可以强制将文件保持为未更改状态(即使它们已经被更改了!)。 - pdem
25个回答

259

我在Windows上遇到了这个问题,但没有准备好研究使用config --global core.autocrlf false的影响,也没有准备好放弃其他私有分支和我的存储库中其他好东西并以一个新的克隆开始。我只是需要立即完成某件事情。

以下方法对我有效,它基于你让git完全重写你的工作目录:

git rm --cached -r .
git reset --hard

(请注意:仅运行git reset --hard不足以解决问题,也不建议在reset之前仅仅使用rm删除文件,尽管这些都被建议在原始问题的评论中)


11
在更改core.autocrlf后,又取得了另一个成功,但没有任何影响。 - Daniel Buckmaster
8
即使在core.autocrlf false的情况下,我在Windows上仍然遇到了这个问题。这个答案是其他方法都不行时才有效的。 - kenchilada
9
我尝试了这个和其他问题的多个建议,这是唯一有效的修复方法。我没有文件属性并且已经将core.autocrlf设置为false。 - BrotherOdin
4
这对我没用。所以我以更加丑陋的方式创建了一个新分支,只是为了提交这些更改,因为它们对我来说无用。[java]git checkout -b a-branch-to-commit-bad-crlf-files[/java][java]git commit -am“提交坏的crlf文件”[/java] - Mohd Farid
5
有时类似这样的问题让我非常怀念 SVN。 - Mike Godin
显示剩余9条评论

143

可能会有多个问题导致这种行为:

换行符规范化

我也遇到过这种问题。它归结于git自动将crlf转换为lf。这通常是由于单个文件中存在混合的换行符引起的。文件在索引中被规范化,但是当git将其再次反规范化以便与工作树中的文件进行比较时,结果会不同。

但如果你想要解决这个问题,你应该禁用core.autocrlf,将所有换行符改为lf,然后再次启用它。或者你可以通过执行以下操作完全禁用它:

git config --global core.autocrlf false

不必使用core.autocrlf,您也可以考虑使用.gitattributes文件。这样,您可以确保使用该仓库的所有人都使用相同的规范化规则,防止混合的行尾进入存储库。

如果希望Git在执行不可逆转的规范化时发出警告,请考虑将core.safecrlf设置为“warn”。

Git manpages中提到:

CRLF转换有一定可能性会破坏数据。autocrlf=true将在提交时将CRLF转换为LF,在检出时将LF转换为CRLF。在提交之前包含LF和CRLF混合的文件无法由Git重新创建。对于文本文件,这是正确的做法:它修正了行尾使得我们在存储库中只有LF行尾。但是,对于被错误分类为文本的二进制文件,转换可能会破坏数据。

不区分大小写的文件系统

在不区分大小写的文件系统上,当存储库中存在大小写不同的相同文件名时,Git尝试检出两个文件,但只有一个文件在文件系统中。当Git尝试比较第二个文件时,它会将其与错误的文件进行比较。

解决方案要么是切换到不区分大小写的文件系统(但在大多数情况下不可行),要么是在另一个文件系统上重命名并提交其中一个文件。


8
好的,那就这样吧...现在git状态显示没有更改。 我已经研究过autocrlf设置,但似乎无法正确操作。 - rbellamy
1
干得好!+1。这又是一个支持我将其设置为false的论据(https://dev59.com/lHM_5IYBdhLWcg3wvF3J#1250133)。 - VonC
3
解决大小写敏感问题的更稳妥方法是不要在你的存储库中有仅以大小写区分的多个文件夹名称 - Ohad Schneider
4
要查找文件名只有大小写不同的文件,可以运行命令 git ls-tree -r --name-only HEAD | tr A-Z a-z | sort | uniq -d。如果要列出这些文件名的大写和小写形式,可以运行命令 git ls-tree -r --name-only HEAD | fgrep -i -f <(git ls-tree -r --name-only HEAD | tr A-Z a-z | sort | uniq -d) | sort -i - Diomidis Spinellis
关于不区分大小写的名称冲突问题的指出 - undefined
显示剩余6条评论

120

对于一些人可能会有用的另一个解决方案,因为我尝试了所有的文本选项都没有起作用:

  1. 用一行替换.gitattributes文件中的内容:* binary。 这告诉git将每个文件都视为无法处理的二进制文件。
  2. 检查那些有问题的文件的消息是否消失;如果没有,可以使用git checkout -- <files>将它们恢复到仓库版本。
  3. git checkout -- .gitattributes.gitattributes文件恢复到其初始状态。
  4. 检查这些文件是否仍未标记为更改。

1
我卡在无法还原、拉取或隐藏文件上已经几个小时了。这对我来说是解决方法!谢谢!(Git 1.8.3.1) - NuSkooler
3
在最终获得成功之前,我尝试了许多事情。谢谢! - ghenghy
1
这是如何工作的?我认为将.gitattributes还原到原始状态会重新引入相同的问题,但不幸的是我的问题现在已经解决了。其他建议在我的情况下都没有起作用。 - SO_fix_the_vote_sorting_bug
1
@jdk1.0 我的理解/猜测是涉及到两种不同的比较方法。当某处存在不同的行尾时,错误就会发生,而Git有时会忽略它。当你询问 git status 时,它会发现它们是不同的文件。当你询问 git checkout 时,它会发现它们具有相同的内容。这个解决方案暂时指示Git忽略任何可能的行尾巧妙之处,并确保你的本地副本与 HEAD 的副本完全一致。一旦解决了这个问题,恢复巧妙之处就可以了,因为它不会添加新的错误。 - zebediah49
3
我花了几个小时来解决这个问题,最终这个解决方案对我起了作用! - Maryam
显示剩余2条评论

79

针对未来遇到这个问题的人:文件模式的更改也可能导致相同的症状。执行 git config core.filemode false 将解决此问题。


3
完成此操作后,您可能需要执行 git checkout . - Marty Neal
5
无需再次检出即可正常运作(原意:对我来说起作用了,无需再次检出) - phillee
3
供日后参考:要确定这是否是您需要的修复(而不是其他答案中的其他修复),请使用 git diff 命令,它将显示具有模式更改的文件,例如 old mode 100755 / new mode 100644 - pgr
这对我来说解决了问题,而其他任何方法都没有用。我真的不认为人们应该在互联网上制作git备忘单和“简易指南”。Git确实不是一件可以轻松掌握和使用的东西,我认为在使用之前必须接受专业的正式培训和实践。 - user5132647
1
谢谢,你救了我很多眼泪! - Lukasz

33

这让我疯狂,特别是在网上找不到任何解决方案的情况下,我终于找到了解决方法。以下是我的解决方案,但由于这是同事的工作,我不能获得功劳 :)

问题源:我最初在Windows上安装git时没有启用自动换行符转换,导致我对GLFW的初始提交没有正确的行结束符。

注意:这只是本地解决方案。克隆代码库的下一个人仍然会遇到这个问题。可以在此处找到永久解决方案: https://help.github.com/articles/dealing-with-line-endings/#re-normalizing-a-repository

设置: Xubuntu 12.04 带有GLFW项目的Git repo

问题:无法重置glfw文件。无论我尝试什么,它们始终显示为修改状态。

解决:

edit .gitattributes

Comment out the line:    # text=auto

Save the file

restore .gitattributes:   git checkout .gitattributes

提及被注释行的内容可能会有所帮助。 - rbellamy
不幸的是,大多数项目都没有这个可选的.gitattribute文件。 - mchiasson
谢谢。我只是不明白为什么这是必要的。 - diogovk
为什么?基本上,这是一种临时解决方案,用于处理行尾。请按照注释中的链接使用永久解决方案。 - Richard Lalancette

12

我有一个.bat文件,遇到了同样的问题(无法在未跟踪文件中删除它)。git checkout --没有起作用,这个页面上的任何建议也都没用。唯一有效的方法是执行:

git stash save --keep-index

然后要删除存储:

git stash drop

这对我有用。请注意,--keep-index很重要。 - filpa
为什么--keep-index很重要? - Choylton B. Higginbottom

10

我有两次相同的问题!都发生在我要隐藏一些已经完成的更改后,试图重新应用它们。但是由于有很多文件被修改了但实际上并没有改变,所以我无法恢复这些更改。

现在我认为我已经尝试了上面列出的所有解决方法,但都没有成功。尝试过之后,

git rm --cached -r .
git reset --hard

我现在修改了存储库中几乎所有的文件。

比较这些文件时,显示我已删除了所有行并添加它们。

有点令人不安。我将来会避免隐藏更改。

唯一的解决方法是克隆一个新的存储库并重新开始。(上次就是这样做的)


6

通常,在GIT中,要清除所有修改和新文件,以下两个命令应该非常有效(请小心,这将删除您可能创建的所有新文件和文件夹,并将所有修改的文件还原为您当前提交的状态):

$ git clean --force -d
$ git checkout -- .

也许有时更好的选择只是使用 "git stash push" 命令,可以选择添加一条消息,像这样:
$ git stash push -m "not sure if i will need this later"

这也会清除您所有新的和修改过的文件,但是如果您想要恢复它们,您可以将它们存储在隐藏区。GIT中的隐藏区可以在分支之间传递,因此如果需要,在不同的分支中都可以恢复它们。

顺带一提,如果您已经将一些新添加的文件添加到暂存区并想要摆脱它们,这个命令可以解决问题:

$ git reset --hard

如果以上方法对您无效,可以尝试以下方法(这是我之前解决该问题的方法):
我以前遇到过几次这个问题。 我目前在使用雇主提供的Windows 10计算机进行开发。 今天,这种特殊的git行为是由于我从我的“develop”分支创建了一个新分支。 出于某种原因,在我切换回“develop”分支后,一些看似随机的文件仍然存在,并在“git status”中显示为“modified”。
此外,此时我无法检出另一个分支,所以我被困在了“develop”分支上。
这就是我做的事情:
$ git log

我注意到今天早些时候从“develop”创建的新分支显示在第一个“commit”消息中,最后被引用为“HEAD -> develop,origin / develop,origin / HEAD,The-branch-i-created-earlier-today”。

由于我实际上不需要它,所以我将其删除了:

$ git branch -d The-branch-i-created-earlier-today

修改后的文件仍然出现,所以我执行了以下操作:
$ git stash

这解决了我的问题:
$ git status
On branch develop
Your branch is up to date with 'origin/develop'.

nothing to commit, working tree clean

当然,$ git stash list 会显示存储的更改内容,因为我没有需要保留的存储内容,所以我运行了 $ git stash clear 命令来删除所有的存储。
注意:我之前没有尝试过他人在此之前建议的做法。
$ git rm --cached -r .
$ git reset --hard

这可能也行,下次遇到这个问题我一定会尝试。

6

尝试执行

git checkout -f

这将清除当前工作目录中的所有更改。


不错!这对我有用。虽然对于一种顽固的情况,我首先必须使用git checkout -f <另一个最近的分支> 然后再回到我的分支 git checkout -f <我正在工作的分支> - Reversed Engineer

4
我只能通过暂时删除我的代码库中的.gitattributes文件(其中定义了* text = auto和*.c文本)来解决这个问题。

删除后,我运行了git status,修改内容已经消失。即使.gitattributes被放回原位,它们也没有再次出现。


这甚至可以处理更复杂的gitattributes,例如过滤器。 - Samizdis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接