无法在git中丢弃更改

9
一两周前,我用一个简单的bash脚本find |sed|tar|xz|gpg对一些文件进行了归档,解压它们并将其内容放入git存储库中,提交更改,然后将下一个归档的内容放入存储库中,再次提交(反复此过程),以便有一个更好的系统。
所有文件都在我的两台计算机上使用Arch Linux,在TeXstudio或Vim中进行编辑。
我试图检出旧版本,但它翻转了——由于未完成的更改,它不会让我检出。我尝试了我所知道的一切,然后上Google查找我不知道的东西。
关于这个问题还有其他一些问题。不幸的是,它们的答案没有帮助到我。为了完整起见,我将列出这些问题。

$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

modified: Arcs/arc1.tex
modified: Arcs/arc2.tex
modified: Arcs/frontmatter.tex

no changes added to commit (use "git add" and/or "git commit -a")

另外,为了方便大家,下面我已经做了显而易见的事情。
git reset --hard
git -a commit
git stash
git pull

同时从索引中删除所有内容并将其重新添加。

无法在GIT中放弃文件更改

我不在Windows上。此外,这与行尾没有任何关系,因为我是唯一的用户。没有理由存在奇怪的行尾。

Git拒绝重置/丢弃文件

git reset --hard HEAD (among other possibilities)

git stash
git stash drop

git config core.autocrlf input
git rm --cached -r .
git reset --hard
git add .
git commit -m "Normalize line endings"

这不仅没有起作用,而且增加了不正常工作的文件数量,并且还为某些原因写入了700多行到一个文件中。它甚至不是那个出问题的文件。

无法在Git中放弃更改

更多的结束行内容。

如何在Git中放弃未暂存的更改?

git clean -df
git checkout -- .
git checkout -- ./.

git checkout-index -a -f

git checkout --force master

我尝试过的但并没有看到的事情

我尝试过提交更改 git commit -am "WORK DAMN YOU!" 然后撤销更改 git revert --hard HEAD^

我还尝试从我的私有远程仓库拉取代码,但是提示本地仓库已经是最新的了。

这真的很令人沮丧。


1
你告诉我们的一切都很好,除了我们真正需要看到的东西——问题开始时 git status 的输出。你能否包含原始的 git status 输出? - Tim Biegeleisen
那我建议您在途中犯了一个错误。我建议的选项都应该有效。 - Tim Biegeleisen
确实他们应该这样做。但是他们没有。这就是为什么我在这里询问。 - Nero gris
我同意@TimBiegeleisen的观点,认为在背后修改文件的东西最有可能是罪魁祸首。如果你无法确定是哪个程序在这样做,尝试在你的工作目录中运行lsof +D .。如果这没有帮助,你应该检查git diff的输出,看看工作目录中的更改是否合理(如果你仍然束手无策,将该输出添加到问题中也可能有所帮助)。 - msbit
确保没有将 core.autocrlf 设置为任何值(特别是 true,但由于您在 Linux 上,因此不需要设置)。确保也没有设置 core.eol。使用 git config --get core.eolgit config --get core.autocrlf 查看它们是否已设置。然后,检查是否有名为 .gitattributes 的文件,可能会为名为 *.tex*.* 的文件设置 filter,因为这些文件也可能会这样做。即使这些情况不太可能发生,请检查不稳定的文件系统、磁盘小精灵或在背后吞噬文件的进程。 - torek
显示剩余7条评论
3个回答

6

尝试使用 git rm --cached -r .

在执行 git reset --hard 后。

这是唯一对我有效的解决方案。 希望能对别人有所帮助!


如前所述,那不起作用。存储在代码库中的副本将与工作副本因过滤器而不同。您可以自由地删除/替换文件,以任何方式,但它们始终会与提交存储的内容不一致。 - Nero gris

3
根据一条评论

它是.git/info/attributes。...为什么会有这样的影响?...我需要那些[*.tex]过滤器...

可以使用它们。 你只需知道Git不理解它们,并且可能需要以某种方式进行调整。 不幸的是,很少有好的替代方法来进行所需的调整。
过滤器(称为cleansmudge过滤器)的工作方式与core.autocrlf和行尾处理的方式直接相关。 要自己了解它们,请从以下几个简单事实开始:
  • 任何Git对象的内容 - 提交、树、blob或注释标签的内容 - 字面上是无法更改的。 这是因为内容是通过其数据库键检索的,该键是哈希ID(当前为SHA-1,将来可能是SHA-3或其他非常好的哈希),必须匹配内容的计算哈希。

  • 您通过其哈希ID检索提交。 像masterdevelop这样的分支名称只包含该分支上最新提交的实际哈希ID。

  • 每个提交都存储其父提交的原始哈希ID,作为其内容的一部分,并存储导致blob对象的树对象的原始哈希ID,从而产生该提交的快照。

要将新对象存储到数据库中,请将对象馈送到git hash-object -w(或Git在内部自行执行此操作)。 Git现在计算内容的哈希,包括给出对象类型和大小的标头,并将值 - 内容 - 存储到数据库中并发出键。 然后,您可以在将来使用键检索内容。 在那时,Git重新检查哈希:它必须与键匹配。 如果不匹配,则数据已损坏,Git将停止。
因此,提交哈希必须与提交内容相匹配,其中包括树内容的树哈希,该树内容的blob哈希。 如果提交本身不是分支的末尾,则通过通过哈希ID向后遍历一些先前的提交来找到提交。 结果数据结构是提供Git数据完整性保证的Merkle Tree
这意味着任何过滤都不能在已提交的内容上完成。然而,必须在已提交的内容上执行过滤,以便Windows用户可以拥有CRLF行尾,Git该如何解决这个悖论?
答案在于Git的另外几个事实:
- 您不能直接使用提交内容进行操作。它们需要被提取到工作区,称为“工作树”。工作树(或工作树,或您想要拼写的其他名称)以未压缩的形式具有提取的文件,可以对其进行读写。 - 但是Git还添加了一个中间数据结构,最初Git只称之为“索引”。这并不是一个很好的名称,因此这种数据结构具有三个名称:它是“索引”,“暂存区”和“缓存”。此索引跟踪工作树,例如缓存“stat”系统调用数据。当前提交的每个文件首先被提取到索引中,在其中保留其特殊的压缩形式 - 实际上,直接使用原始blob哈希ID - 以使索引具有或确切地说是引用提交中文件的副本。
- 在文件上运行git add将文件复制到索引中(实际上是将其作为blob对象添加到主数据库并计算其哈希ID,然后在索引中更新哈希ID)。这意味着索引始终是Git将用于下一个可提交的映像。这就是它得到“暂存区”名称的地方。因为您可以使用git add覆盖索引文件,所以它们在此处是可写的,而在提交中则不可写。 - 运行git commit将当前索引打包成树对象,冻结它并永久保存 - blob哈希值现在不再可更改 - 并使用树对象创建新提交。
这个索引是Git获得其速度的方式之一,与其他版本控制系统相比。由于索引跟踪工作树,因此Git可以比通常快得多地执行许多操作:例如,git status可以对目录或文件调用stat并将结果与缓存的stat数据进行比较,而无需读取文件本身。
(索引在冲突合并期间还承担了扩展角色。虽然这与clean和smudge过滤器及LF / CRLF战争无关,但在我们谈论索引时也值得提一下。索引不仅对应每个要提交的文件一个条目,它可以保存三个不要提交的条目:一个来自合并基础,一个来自正在合并的两个分支的每个分支顶部。)

过滤器的工作原理

现在我们已准备好看一看过滤器是如何真正工作的。让我们概括一下关于提交、索引和工作目录的关键要点:

  • git checkout 命令会将提交的树形结构复制到索引中,此时索引内容与提交的树形结构完全相同,但更适合于跟踪工作目录。
  • git checkout 同时还会 将每个提交的文件复制到工作目录中,并更新该文件在索引中的槽位。
  • git add 命令会将文件从工作目录复制回索引中,以便未来的 git commit 命令可以直接冻结索引。

现在,请记住,在将提交内容转换成工作目录文件时,smudge 过滤器 会应用于提交的内容。当 CRLF 行尾换行符需要变成 LF 行尾时,smudge 过滤器 会生效。而在将工作目录内容转换为提交内容(或者至少是待提交内容)时,clean 过滤器 会生效。CRLF 行尾换行符需要变成 LF 行尾时,clean 过滤器 会生效。

在文件被展开到工作目录时应用 smudge 过滤器是理想的时间点在文件被压缩到索引中时应用 clean 过滤器是理想的时间点。所以这就是 Git 的操作时间点。

同时,索引的一个关键特征是 速度。因此 Git 假设 应用 smudge 过滤器不会以某种方式“更改”文件。尽管工作目录文件的内容可能与解压缩的 blob 不匹配,但至少按照意图和目的,它仍与清理并重新压缩工作目录文件后得到的内容匹配。

问题出在这个假设不成立的情况下。如果清理并重新压缩文件导致生成了具有不同哈希 ID 的不同内容,那么答案是: Git 可能会注意到这一点,但也可能不会注意到这一点,这完全取决于索引作为缓存的有效性以及索引中保存的 stat 数据与稍后系统调用提供的 stat 数据之间的差异。

如果污点和清洁过滤器是完美的镜像——这意味着一个被弄脏并重新清洗的文件总是与原始文件匹配,你可以在提取后使用git add将该文件添加到Git中,并更新保存的stat数据。只要它不再改变,Git现在将认为该文件是干净的。如果底层文件系统具有不可靠的stat数据,则可以使用索引的assume unchanged位来强制Git仍然认为该文件是干净的。这是相当粗糙和不太令人满意的解决方案,但它能够胜任工作。

2

Try git config --global core.autocrlf true


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