问题描述
当尝试通过 git reset 恢复到之前的提交(例如 123abc)时
git reset --hard 123abc
git commit -a -m "revert to 123abc"
我不能推动这个(我需要先拉动,拉动才能让我向前)。 我带着这几行来:
for i in `git diff --name-only 123abc`; do git checkout 123abc $i; done
git commit -a -m "revert to 123abc"
从现在开始有效
git diff --name-only 123abc
为空
我想知道这是 hack 还是 git 方法。如果不是, 如何正确完成此操作?
解决方法
当尝试恢复到之前的提交(例如 123abc)时......
我在这里强调的介词“to”(如revert to)至关重要。您链接的问题 (accepted answer) 中的 How do I revert a Git repository to a previous commit? 说明了这一点:
这在很大程度上取决于您所说的“还原”是什么意思。
在一次提交上运行 git revert
可能还不够。如果需要,请参阅有关还原多次提交的答案。
运行 git reset --hard
可能就足够了,但会引入您遇到的问题。这里需要理解的事情是:
-
分支名称只是让 Git 找到一个特定的提交。我们说分支名称指向提交。使用
git reset
,我们可以更改某个分支名称指向的特定提交。 存储库中尚未发生任何其他事情,尽管根据您运行的git reset
类型,在git reset
完成之前可能会发生其他事情:此 {{1} 的第一步} 只是改变你自己的一个分支名称。由于您正在考虑(或已经使用)git reset
,因此您的存储库中会有更多内容发生变化,但目前它们不那么重要。 -
每个 Git 存储库都有自己的分支名称。移动一个您的分支名称不会影响任何其他存储库。
-
您需要做的是让其他一些 Git 存储库更改它的分支名称之一。这就是您遇到此问题的地方:
我不能推动这个(我需要先拉动,拉动才能让我向前)。
--hard
命令是你如何询问——或者使用git push
命令——其他一些 Git 存储库来更改或创建或删除它的一些名称(分支名称、标签名称和其他类似的名称)名称)。但是每个 Git 存储库都设置为轻松接受新的传入提交,但同时,拒绝丢弃任何现有提交的建议。
当您使用 --force
将您的一个分支名称“向后”移动时,以便恢复到(而不是 git reset
add-a-commit-that-backs-out) 一些先前的提交,你故意丢弃一些现有的提交。由于您控制自己的 Git 存储库,因此您绝对可以对自己的存储库执行此操作。由于 revert
命令意在进行这种丢弃,1它毫无怨言地这样做了。但是git reset
不是,而且他们的 Git 会抱怨。
一旦您使用 git push
,他们的 存储库就会让您放回您从自己的存储库中剪下的所有提交。毕竟,Git 旨在尽可能轻松地添加 提交!这让你处于你所处的境地。
您现在有一个选择:
-
强制另一个 Git 存储库放弃一些提交。这需要足够的权限。这也意味着使用其他 Git 存储库的其他人需要对他们制作的任何克隆采取行动,因为他们的克隆会热情地放回您试图修剪的所有提交。所以这对其他人来说有点意思。
-
或者,使用
git pull
或其他一些命令向您的存储库添加一些提交,最终将文件放回,但不要删除任何旧提交。新提交只是添加到旧提交。对于任何想要询问(git revert
)或使用它们(例如,git log
)的人来说,旧的仍然存在。
添加新的提交是 Git 的设计目的,所以后者是要走的路,除非有一些非常充分的理由放弃旧的提交。
作为您链接笔记的问题,所有这些通过未发布提交变得容易得多:只有您拥有的提交,在您自己的私有存储库中,只是不在任何其他 Git 存储库中。如果你从你自己的分支上删除这些提交,没有人会知道。他们不会能够反对 git switch --detach hash-id
将这些提交从他们的分支上删除,因为这些提交不是在他们的分支上。 (同样,每个分支名称对于每个 Git 存储库都是本地的。一个存储库可以向另一个存储库显示存储在其分支名称中的提交哈希 ID,但每个存储库负责将自己的哈希 ID 保存在自己的分支名称。提交被共享;分支名称不会。)
由于您正在查看的提交是已发布,因此您不能使用此快捷方式。
1这使得 git push
成为一种非常强大的工具,就像某种火焰喷射链锯,或工业钢切割激光器,或其他东西。这种强大的功能是 Git 2.23 现在拥有 git reset
的部分原因:您可以做的一些事情,过去需要使用 git restore
,现在可以使用更温和的 { {1}}。如果您询问这两个命令,都会丢掉正在进行的工作,但 git reset
更像是手锯、断线钳或类似的东西。
这是一个黑客。使用
git revert <commit hash>
但要注意,您正在还原 <commit hash>
应用的更改,因此要还原到以前的提交,请使用
git revert HEAD
这将创建另一个提交,以恢复由上次提交引起的更改。检查这个答案:https://stackoverflow.com/a/22683231/12118546
以上是如何做到这一点的正确方法,同时将自身还原到历史中。如果你是唯一一个在 repo 中工作的人,你也可以强制推送删除最新提交的分支:https://stackoverflow.com/a/31937298/12118546
,您应该尝试使用 git revert <commit hash>
。这将还原选定的提交,然后您可以推送更改