git 重置为上一次提交,然后推送

Posted

技术标签:

【中文标题】git 重置为上一次提交,然后推送【英文标题】:git reset to previous commit and then push 【发布时间】:2021-08-12 18:12:19 【问题描述】:

当试图通过 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 方法。如果不是, 如何正确地做到这一点?

【问题讨论】:

如果您正在重置,则无需再次提交。 @evolutionxbox 但我无法推动。我希望 origin 知道我要重置的事实。 通过重置您正在更改提交树。遥控器可能拒绝推送。您可以强制推送,删除远程分支并再次推送,或者使用还原而不是重置。 【参考方案1】:

当尝试将恢复到之前的提交(例如 123abc)时...

我在此处添加的对介词“to”的强调至关重要,就像在 revert to 中一样。链接问题 (How do I revert a Git repository to a previous commit?) 中的 accepted answer 指出这一点:

这在很大程度上取决于您所说的“还原”。

单个提交上运行git revert 可能不够。如果需要,请参阅那里有关还原多个提交的答案。

运行git reset --hard 可能就足够了,但会引入您遇到的问题。这里要理解的是:

    分支名称只是让 Git 找到一个特定的提交。我们说分支名称​​指向提交。使用git reset,我们可以更改某些分支名称指向的特定提交。 存储库中还没有发生任何其他事情,尽管取决于您运行的git reset 的类型,在git reset 完成之前可能会发生其他事情:这个git reset 的第一步只是改变您自己的分支名称之一。由于您正在考虑(或已经使用)--hard,因此您的存储库中会发生更多变化,但目前它们不太重要。

    每个 Git 存储库都有自己的分支名称。 移动一个您的 分支名称不会影响任何其他存储库。

    您需要做的是让 其他 Git 存储库 更改 分支名称之一。这就是你遇到这个问题的地方:

    我无法推动这个(我需要先拉,然后拉才能让我向前)。

    git push 命令是您询问或使用--force 命令的方式来更改或创建或删除其某些名称(分支名称、标签名称和其他此类名称)的其他 Git 存储库。但是每个 Git 存储库都设置为轻松接受新的传入提交,但同时,拒绝丢弃任何现有提交的建议

当您使用git reset 将您的分支名称之一“向后”移动时,以便恢复到(不是 revert,如 add-a- commit-that-backs-out) 一些以前的提交,你故意丢弃一些现有的提交。由于您控制自己的 Git 存储库,因此您绝对可以对自己的存储库执行此操作。由于git reset 命令是意味着 进行这种丢弃,1 它毫无怨言地这样做了。但是git push不是,并且他们的Git 抱怨。

一旦您使用git pull他们的 存储库会让您放回您从自己的存储库中截取的所有提交。毕竟,Git 旨在尽可能轻松地添加提交!这让你处于你所处的境地。

你现在有一个选择:

强制其他 Git 存储库放弃一些提交。这需要足够的权限。这也意味着使用其他 Git 存储库的其他人需要对他们所做的任何克隆采取行动,因为他们的克隆会热情地放回您尝试修剪的所有提交。所以这对其他人来说有点卑鄙。

或者,使用git revert 或其他命令向您的存储库添加一些提交,最终将文件放回,但不要删除任何提交。新的提交只是添加到旧的。旧的仍然存在,任何想询问它们(git log)或使用它们(例如git switch --detach <em>hash-id</em>)的人。

添加新的提交是 Git 的设计初衷,所以后者是可行的方法,除非有非常充分的理由放弃旧的提交。

作为您链接注释的问题,使用 未发布 提交可以轻松实现所有这些:只有您拥有的提交,在您自己的私有存储库中,很简单不在任何其他 Git 存储库中。如果您将这些提交从自己的分支中删除,那么没人会知道。他们将无法能够反对git push 将这些提交从他们的分支中删除,因为这些提交不在他们的分支上。 (同样,每个 branch name 对于每个 Git 存储库都是本地的。一个存储库可以向另一个存储库显示存储在其分支名称中的提交哈希 ID,但每个存储库都负责将自己的哈希 ID 保存在自己的分支名称。提交被共享;分支名称不共享。)

由于您正在查看的提交已发布,因此您无法使用此快捷方式。


1这使得git reset 成为一种非常强大的工具,就像某种喷火电锯、工业钢材切割激光或其他东西。这种过度强大的特性是 Git 2.23 现在拥有 git restore 的部分原因:您可以做的一些事情,过去需要使用 git reset,现在可以使用更温和的 git restore 来完成。如果你问这两个命令会丢弃正在进行的工作,但git restore 更像是手锯,或断线钳,或类似的东西。

【讨论】:

这是一个非常好的和详细的解释。我特别喜欢 git reset 与火焰喷射电锯或工业钢切割激光器的比较但是,您没有说强制 git push 删除原点提交的命令。是 git push --force 吗? @EthanGroat: 是的,git push --force(这是没有任何双重检查方法的原始蛮力),或git push --force-with-lease(允许您一路插入双重检查),或者新奇的@ 987654348@(类似于--force-with-lease,在使用新的git maintenance 套件进行后台获取更新时引入)。【参考方案2】:

这是一个黑客。使用

git revert &lt;commit hash&gt;

但请注意,您正在恢复 &lt;commit hash&gt; 应用的更改,因此要恢复到以前的提交,请使用

git revert HEAD

这将创建另一个提交,该提交正在恢复由上次提交引起的更改。检查这个答案:https://***.com/a/22683231/12118546

以上是一种正确的方法,可以将自身恢复到历史记录中。如果您是唯一在 repo 中工作的人,您还可以强制推送已删除最新提交的分支:https://***.com/a/31937298/12118546

【讨论】:

什么是 hack? @evolutionxbox:Hack = 以无意的方式滥用系统来实现您的目标。 对不起,我明白这个词的意思。我想知道您认为上述问题中的黑客行为。没有以非预期的方式使用。 好吧,OP 创造了他的方式git revert。语言学不是精确的科学,但我认为这是恢复提交的一种骇人听闻的方式...... 重置是一种有效的方法。这是OP不知道如何完成任务。 ***.com/questions/4114095/…【参考方案3】:

您应该尝试使用git revert &lt;commit hash&gt;。这将还原选定的提交,然后您可以推送更改

【讨论】:

我不能推:有人告诉我我落后了,我必须先拉再推。这让我远离了我想要推送的提交 你有没有试过做 git pull 然后做我上面描述的 git revert 是的,当然,我进入了一个无限循环:revert,pull,revert,pull,...关键是revert后我无法推动,一旦拉动,我就会移动到树枝的尖端。 也许尝试做 git pull 然后git reset --hard &lt;commit hash&gt; 我会尽力让你知道

以上是关于git 重置为上一次提交,然后推送的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 git reset 在不丢失本地更改的情况下重置未推送的提交

tortoiseGit 重置为以前的版本

如何删除推送的 git 合并提交

我如何重新推送先前的提交?

sh 重置未推送提交

sh 如果您提交并且不推送某些内容并希望重置提交。