将git仓库重置到特定分支的特定提交

3
我正在处理一个处于以下状态的分支。
        A'--B'--C'--D'
       /
A--B--C--D

发生了一些非常糟糕的事情,我需要回到本地和远程的B',以便远程存储库如下所示。

         A'--B'
        /
 A--B--C--D

对于本地代码库,我进行了以下操作

git reset --hard <sha>

但是我如何为远程仓库做到这一点?

我应该能够做以下操作:

git push origin mybranch --reset

但在手册中没有相关说明。

我尝试创建一个提交,以取消之前的提交,但是:

git add .

报告没有更改(因为我正好处于上一个推送之后,所以预期是如此)。

那么我该如何重置远程仓库呢?


一个额外的问题是:有没有办法从git历史记录和git日志中删除D'和C'提交,使它们好像从未发生过一样? - ndp
2个回答

4
要覆盖追踪的远程分支,请执行 git push origin --force mybranch。(或者使用-f代替--force,或在分支名称前加上+git push origin +mybranch。)
请注意,您应该警告任何可能更改您的分支的合作者,它已经被远程更改,这样他们就不会再次覆盖它。因为 git push 在他们的本地副本中对远程分支进行快进操作,除非您至少对其进行了一个新提交,并且git pull 不会更新他们的本地分支版本。合作者应该执行:
git fetch origin
git checkout mybranch
git rebase origin/mybranch

更新以完整: 如@CodeGnome所建议的,要完全从存在中删除提交,请在包含它们的所有Git存储库上运行git prune --expire now。但请注意,此命令将从Git中删除所有悬空对象,并防止在运行之前“丢失”的任何数据的恢复。通常情况下没问题,但还是需要警告您。

更新:如页面所建议的,git prune --expire now将不会从reflogs中清除提交。请参见链接了解解决方案。对于一种较少侵入性的解决方案,请尝试git reflog expire --all mybranch。在运行git prune之前,您必须这样做。

有时更倾向于明确生成一个“撤销”提交,以删除更改(因此旧版本和其删除的事实在历史记录中可见)。有一个git revert命令可以实现这一点。

3

从历史记录中删除提交

你只需要在B'分支上,然后使用git push --force覆盖该分支的当前提交指针即可。如果您没有将远程设置为跟踪分支,则可能需要使用git push --force origin <branchname>

C'和D'将保留在reflog中,并作为对象存储在仓库中,直到它们最终被修剪,但除非您开始深入研究,否则不应出现在任何日志历史记录中。

从仓库中删除悬空对象

如果您想完全将C'和D'从仓库中删除,可以在两个仓库中调用git prune --expire now。这应该会完全删除悬空对象。


请注意,除非你有充分的理由,否则不要调用 git prune 命令——它会销毁垃圾对象,而这些对象在使用 Git 恢复丢失的数据时非常有用。 - Alexander Gladysh
@AlexanderGladysh 这正是git-prune(1)的用例:完全删除悬空对象,这就是OP所要求的。此外,请注意,如果悬挂提交已打包,可能需要运行git-repack(1)和git-prune-packed(1)。 - Todd A. Jacobs
@CodeGnome 尽管如此,我认为在这种情况下需要发出警告 - git prune将删除所有悬空对象(通常是可以的,但您必须知道自己在做什么)。 - Alexander Gladysh

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