Git:如何还原2个顽固地卡在“已更改但未提交”的文件?


84

我有一个回购,其中有两个文件,据说我是在本地更改的。

所以我被困在这里:

$ 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")

Doinggit diff表示整个文件内容都发生了变化,尽管从目光投向它似乎是不正确的(diff似乎看不到,这似乎是常见的行范围)。

有趣的是,我不记得在本地更改这些文件。该仓库与一个远程仓库(私有,在GitHub.com,FWIW)一起使用。

无论我尝试了什么,我都不能放弃这些本地更改。我已经尝试了所有:

$ 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

换句话说,我已经尝试了如何丢弃Git中未分级的更改中介绍的所有内容还有更多。但是,这两个文件仍然停留在“已更改但未提交”状态。

到底是什么原因导致两个文件像这样被卡住,看似“不可还原表”?

PS在上面显示了我已经尝试过的命令的列表中,我误解了git revert我的意思git checkout。对不起,我要感谢那些回答我应该尝试的人checkout。我编辑了问题以更正它。我肯定已经尝试过了checkout


请问git diff --ignore-space-changegit diff --ignore-all-space使输出端的区别git diff
2011年

@jermiahd是的!带有任一标志git diff的文件表示相同。
格雷格·亨德肖特2011年

2
可能是stackoverflow.com/questions/2016404/…的副本。无论如何,我还是更喜欢在那里接受的答案,那就是设置git config --global core.autocrlf false而不是“ true”。
2013年

2
答案[这里] [1]对我和其他许多人都有效。[1]:stackoverflow.com/questions/2016404/...
麦克ķ

2
在不区分大小写的文件系统中检出同一目录中包含2个或多个文件且大小写不同的存储库时,也会发生这种情况。删除或重命名文件之一以解决此问题。
465544

Answers:


33

文件中的行尾是什么?我敢打赌他们是CRLF。如果是这样,请查看此指南:http : //help.github.com/line-endings/

简而言之,您需要确保将git设置为在提交时将行尾转换为LF,然后提交那些文件。假设您正确设置了git,存储库中的文件应始终为LF,检出的文件应为操作系统的本机文件。


1
谢谢。我已经拥有了git config --global core.autocrlf true,另一方也可以在GitHub上推送到仓库。
格雷格·亨德肖特2011年

1
然后,您只需要执行该<pre>指南最后一部分中的操作,即可修复存储库中的文件。
2011年

5
我不同意行尾在回购中应始终为LF(尤其是在其他人已经提交CRLF的情况下),并且OS应该始终是本机的。我的Windows编辑器和环境(主要用于PHP,HTML,CSS等)可以很好地处理LF行尾。
西蒙东

一个天才的答案,我忘记了我最近使用gitattributes在回购文件中强制使用LF,并且不希望git自动更改文件。我们拥有Windows和Linux开发人员的混合体,这使我们发疯,因为不同平台上的编辑人员不断更换行终止符,而一旦这种变化在所有这些方面都荡然无存。
奥利弗·邓吉

120

我花了数小时试图解决一个类似的问题-我签出的一个远程分支,即使删除了所有文件并git checkout -f再次运行(或这篇文章的其他变体),它仍然顽固地将四个文件显示为“已更改但未更新” !

这四个文件是必需的,但我肯定没有对其进行修改。我的最终解决方案-说服Git他们没有被更改。以下内容适用于所有检出的文件,显示“已修改”状态-确保已提交/存放了真正修改过的文件!:

git ls-files -m | xargs -i git update-index --assume-unchanged "{}"

在Mac OSX上,xargs的操作略有不同(请评论Daniel):

git ls-files -m | xargs -I {} git update-index --assume-unchanged {}

我已将其添加为下一次自己的占位符,但我希望它也对其他人有所帮助。


9
我有几个顽固的文件并运行了此命令,git status现在没有变化,但是当我尝试更改分支时,git仍然告诉我我无法更改分支,因为这两个文件具有本地更改。不知道我做错了什么,但似乎只是掩盖了问题,而不是解决问题?运行该命令后,我也无法提交文件。我的解决方案是删除它们,提交和交换分支。
RodH257

5
谢谢!我尝试了所有我能找到的其他答案中提到的所有技巧-没有一个起作用。在Mac上无法按原样使用该行,只需在每个文件上运行git update-index --assume-unchanged <filename>,这便使问题消失了。
Yonatan Karni 2014年

2
当您希望对此文件进行本地修改时,不要使用“-假定不变”选项吗?就像您检出模板网站配置文件并用不应该存储在存储库中的敏感信息更新它一样?
Maxime Rossini 2014年

6
这正是我所需要的,尽管Mac上的xargs似乎有一些不同(我正在运行10.10优胜美地)。这终于对我git ls-files -m | xargs -I {} git update-index --assume-unchanged {}
Daniel

3
恢复命令的效果:git ls-files -v|grep '^h' | cut -c3- | xargs -i git update-index --no-assume-unchanged "{}"
Marinos

20

这就是我解决同一问题的方式:打开.gitattributes更改:

* text=auto

至:

#* text=auto

保存并关闭,然后还原或重置,感谢@Simon East的提示


1
删除text=auto.gitattributes中的设置对我有用,然后在我git reset --hard将该设置放回原位后,文件不再显示为已修改!
ErikE

1
text=auto设置显然存在问题。我正在使用来自多个操作系统的提交进行回购,但我仍然没有弄清楚是什么导致我更多的问题:保留还是删除它。
Marinos

1
@Marinos是的,具体地说,git允许您在首次添加此设置时以错误的行尾保留现有文本文件。这是错误的,除非您记得自己这样做,否则最终将遇到这些不可恢复的更改之一。
罗曼·斯塔科夫

12

另一种可能性是差异(这是防止您使用checkout命令还原这些文件)是文件模式之一。这就是我发生的事情。在我的git版本中,您可以使用

git diff dir1 / foo.aspx

它将显示文件模式更改。不过,它仍然不会让您还原它们。为此使用

git config core.filemode为false

或在文本编辑器中通过添加来更改git .config

[核心]

filemode = false

完成此操作后,您可以使用

git reset HEAD dir1 / foo.aspx

文件应该消失了。

(我从如何使git忽略模式更改(chmod)的答案中获得了所有这些信息


1
如果您使用的是Windows,则应首先
尝试

要特别小心,不要使用cmd.exe中的cygwin git。如果要在cmd.exe中使用git,请安装msysgit。
AlcubierreDrive 2013年

只是为了确认这确实是Windows上的问题。
DejanMarjanović'14

对于Windows上的我来说,这不是问题(core.filemode已经设置为false)。就我而言,解决方案/解决方法就是Alan Forsyth的答案
Venryx

3

尝试还原本地更改

git checkout -- dir1/foo.aspx
git checkout -- dir2/foo.aspx

我的大脑“恢复”了,我打算写作checkout。我已经尝试过了checkout。无论如何,谢谢您的回答。这是对我最初的问题的一个很好的答案,所以我会投票赞成。
格雷格·亨德肖特2011年

3

我有一些幻像更改的文件,显示为已修改,但实际上是相同的。

运行此命令有时可以起作用:(
关闭git的“智能”功能,但通常对行尾无用转换)

git config --local core.autocrlf false

但是在另一种情况下,我发现这是由于.gitattributes根目录中的文件存在一些行尾设置,autocrlf即使关闭了该文件,它仍试图应用某些文件。这实际上并没有帮助,所以我删除了.gitattributes,提交了,并且文件不再显示为已修改。


删除text=auto.gitattributes中的设置对我有用,然后在我git reset --hard将该设置放回原位后,文件不再显示为已修改!
ErikE


2

您可能还遇到了与目录字母大小写有关的问题。您的某些同事可能已将目录名称从例如myHandler更改MyHandler。如果以后再推和拉原始目录的某些文件,则在远程存储库中将有2个单独的目录,而在本地计算机上只有1个目录,因为在Windows上,您只能只有1个。而且你有麻烦了。

要检查是否是这种情况,只需查看远程存储库是否具有双重结构。

要解决此问题,请在回购之外创建父目录的备份副本,然后删除父目录,然后将其推送。拉动(这是第二个标记为已删除的标记应出现在状态上的情况),然后再次推动。之后,从备份中重新创建整个结构,然后再次推送更改。


2

我认为提供提示如何重现该问题将很有帮助,以便更好地理解该问题:

$ 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

复制的第二种方法: 在上面的脚本中,
echo "*.txt -text" > .gitattributes
将以下行替换为,
git config core.autocrlf=false
并保留其余行


以上都是怎么说?可以(在某些情况下)使用CRLF提交文本文件(例如,-text.gitattributes/或中core.autocrlf=false)。

当我们以后想将同一文件视为文本(-text-> text)时,将需要再次提交。
当然,您可以暂时将其还原(由Abu Assar正确回答)。在我们的情况下:

echo "*.txt -text" > .gitattributes
git checkout -- 1.txt
echo "*.txt text" > .gitattributes

答案是:您是否真的要这样做,因为每次更改文件都会引起相同的问题。


作为记录:

要检查哪些文件会在您的仓库中导致此问题,请执行以下命令(git应使用--with-libpcre进行编译):

git grep -I --files-with-matches --perl-regexp '\r' HEAD

通过提交文件(假设您要将其视为文本),与执行此链接http://help.github.com/line-endings/中提出的用于解决此类问题的建议相同。但是,除了删除.git/index和执行之外reset,您只需更改文件,然后执行git checkout -- xyz zyf然后提交即可。


2

我遇到了同样的问题,有趣的是,文件在Windows上更改了,但是从WSL中查看文件时却没有更改。没有任何混乱的行尾,重置等能够改变它。

最终,我在此答案中找到了解决方案。以下是为方便起见的文本:


我已使用以下步骤解决了此问题

1)从Git的索引中删除每个文件。

git rm --cached -r .

2)重写Git索引以拾取所有新行结尾。

git reset --hard

解决方案是git网站https://help.github.com/articles/dealing-with-line-endings/上描述的步骤的一部分



1

由于git将大小写差异视为不同的文件,而Windows将它们视为同一文件,因此也可能导致此问题。如果仅更改了文件名的大小写,则该存储库的每个Windows用户都将遇到这种情况。

解决方法是确认文件内容正确,然后重新提交。由于两个文件的内容不同,因此我们必须将它们合并在一起。然后拉,将存在合并冲突,您可以通过删除重复的文件来解决。重新提交合并分辨率,您将回到稳定状态。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.