问题描述
我想将本地文件推送到 GitHub 存储库,但我使用了:
git checkout -m filename
所以,我的本地文件被覆盖了。我想知道如何从中恢复。
解决方法
您需要在对文件进行更改之前签出您正在进行的提交,然后再次提交。假设文件名为 filename 并且您在提交 1 上:
git checkout HEAD^
git commit -a
git push -f
总而言之,当您检出较旧的提交时,您正在提交自该提交以来所做的所有更改。如果您不想进行这些更改,则必须使用 -f 选项来强制提交。
,...我的 [working tree] 文件被覆盖了。我想知道如何从中恢复。
Git 在这里几乎没有帮助(尽管参见脚注 2)。工作树中的文件(您可以查看、读取和写入的文件)实际上并不在 Git 中。充其量,它们是在更早的时候从 Git 复制。如果您想要再次从 Git 复制文件out,git checkout
——或者,在 Git 2.23 或更高版本中,git restore
1——让你做吧。但是,如果您的工作树中有未保存的工作,并告诉 Git 销毁它,而 Git 做了......好吧,在这种情况下,Git 并没有先将未保存的工作保存在任何地方。所以你不能从 Git 取回它。
如果您使用的是 macOS 并且有 Time Machine 备份,请查看是否可以从那里获取旧版本的文件。如果您使用的是其他操作系统,请查看该操作系统的备份工具。 操作系统可能会给您一种方法来恢复文件的旧版本。
我想将本地文件推送到 GitHub 存储库...
请注意,Git 不会推送文件。 Git 推送提交。每个提交都包含每个文件的完整快照。要更新某个文件,您需要检查整个提交——所有 文件——以便 Git 将它们从某个提交中复制到您的工作树中。这些文件不在 Git 中:它们实际上对工作很有用。
Git 提交中的文件是只读的、永久冻结的格式,只有 Git 可以读取并且实际上没有,甚至 Git 本身都不能覆盖,所以它们'对于做任何实际工作都毫无用处。这就是为什么 Git 必须将它们复制到某个地方。
无论如何,既然文件在你的区域——你的工作树——你可以处理它们。当您更新了一些文件集时,您必须运行 git add
来让 Git 为提交做好准备。这会压缩(或我有时喜欢说的“冷冻干燥”)工作树文件,使其准备好进入您的下一个提交。在此之前,准备好进入 next 提交的文件的冻干副本或压缩和重复数据删除副本仍然与 this 中的副本相同 提交。
既然您已经更新了提议的下一次提交,并且 git status
表明这些文件已“暂存以进行提交”——这仅意味着 Git 索引中的冻干文件aka staging-area 不再匹配 current 提交中的冻干文件——运行 git commit
将收集 Git 进行新提交所需的其余部分(“元数据”)。然后它会写出那个新提交,它将保存每个文件的快照——去重,这样你的新提交与当前提交匹配,几乎不需要磁盘空间——并且你的新提交提交将成为您当前的提交。 现在您可以git push
:提交。
不过,在您提交之前,您的工作树中的文件只是在您的工作树中。2
1请注意,git checkout
在 Git 2.23 及更高版本中仍然存在。它刚刚也被拆分为“安全”命令 git switch
和“不安全”命令 git restore
,这样您就不会意外运行不安全的 { {1}} 同时认为您正在运行安全命令。
此处引号中的安全和不安全修饰符指的是 git checkout
试图确保 Git 不会破坏工作树中任何正在进行但未提交的工作的方式,而 git switch
假定您了解您刚刚要求销毁正在进行的工作,并且很乐意这样做。 git restore
命令结合了这两个操作:有一种“安全”形式的检出首先检查它是否会破坏未保存的工作,还有一种“不安全”形式假设您确实有意销毁未保存的工作。
2如果你有运行git checkout
,在这个覆盖工作树副本的git add
之前,有 一些希望。这有点复杂,但是当 git checkout
获取您的工作树文件并对其进行冷冻干燥时,它必须将冷冻干燥的副本保存某处。 Git 保存它的位置在存储库中。因此,git add
实际上将文件的副本放入存储库中。
恢复这样的文件有一些绊脚石:
-
文件的名称在存储库中not:
git add
步骤将文件的名称保存在 Git 的 index 中又名暂存区,创建或更新模式名称哈希元组。git add
将替换该索引条目,因此无需再查找 mode-name-hash 元组。 -
内容将被自动去重。如果它们匹配任何更早提交,则意味着哈希将是来自某个更早提交的哈希,其余的不会有任何好处:内容是在Git 存储库,但这里的这个小技巧无济于事。
如果这些绊脚石不是什么大问题,那么运行 git checkout
将使 Git 搜索整个 Git 对象数据库并找到任何所谓的悬垂的 blob。其中之一将是您的文件内容。它们都没有有用的名称,但所有这些都将在从冻干格式扩展后复制到 git fsck --lost-found
中。因此,您现在可以仔细阅读 .git/lost-found/other
中的所有文件,看看其中是否有您想要返回的内容。如果是这样,请将该文件复制到某处。然后只需删除 .git/lost-found/other
目录中的整个 other
和 commit
目录,以撤消此处 .git/lost-found
的影响。 (或者,如果您不介意它们占用额外的磁盘空间,就不用它们。)