[英]How to revert pushing local branch to remote master
1)我已将本地分支推送到原始主机,而不是远程分支。
2)然后我将本地分支按原样推送到远程分支
但:
如何在不弄乱的情况下删除第一个动作?
您必须先弄乱,才能解决此问题,因为已经弄乱了。 在您陷入混乱之前,最后的故障保险是推送到共享远程服务器。
所以问题是,如何最好地清理混乱。 有两种选择。
一种选择是进行历史记录重写。 这将产生“最干净的”最终结果,但需要与存储库的每个用户进行协调。 如果您无法与可能拥有该存储库克隆版本的所有人进行协调,那么您将无法安全地进行历史记录重写(如果尝试进行历史记录重写,那么无论如何它都可能最终被撤消)。
另一个选择是添加新的提交以达到所需状态,从而留下“混乱”的历史记录。 这不是很好,但是对于共享存储库,它确实会在没有大量协调工作的情况下“自行整理”,而历史重写就不会。
历史重写
“历史记录重写”是从分支机构的历史记录中删除提交的任何操作。
O -- x -- x <--(master)(origin/master)
\
A -- B -- C <--(branch)
而您不小心将branch
推到了origin/master
,给了您
O -- x -- x <--(master)
\
A -- B -- C <--(branch)(origin/master)
就远程而言, A
, B
和C
现在是master
一部分,因此要撤消操作,您可以从原始master
删除A
, B
和C
,但这是一个历史重写。
重写会产生最干净的结果,但是,如果(a)您独自使用遥控器,或者(b)小型(或最多中等规模)团队共享遥控器,以便您可以合理地协调,那么重写实际上是一个合适的解决方案与所有团队成员一起。
历史记录重写的问题是,它导致分支以意外的方式移动; 如果git将此动作视为例行程序,则会导致并发的更改例行丢失-与分支和合并的目的相反。
您可以通过多种方式在本地重写历史记录-但是在这种情况下,您不必这样做,因为本地分支已经处于正确的状态。 但是,要使远程服务器重写其分支的历史记录,您必须执行“强制推送”,根据origin
回购协议的设置方式,您可能会或可能不会被允许这样做。
如果您被允许这样做,那么第一步就是要与回购的所有用户交流将要进行历史重写的情况(最好是说明发生了什么,为什么需要重写以及何时进行重写) )。 这是因为一旦您进行重写,将A
, B
和C
任何A
拉入其master
副本中的任何人都将处于“中断”状态,并且必须执行本地清理过程。
您可以在git rebase
文档中的“从上游rebase恢复”下阅读有关该问题以及如何清除它的更多信息。 (这记录在rebase
下,但适用于任何远程历史记录重写。)请注意,该repo的任何用户都可能会错误地执行清理操作,从而使问题永久存在并可能撤消重写。
一旦所有人都参加了会议,您将
git checkout master
git push --force-with-lease origin master
只要没有人推其他更改origin/master
之上C
,这应该移动origin/master
回到原来的位置,并根据需要其他用户就可以开始清理其本地状态。
请注意, --force-with-lease
-f
--force-with-lease
替换了较早的--force
(或-f
)选项,该选项不太安全,因为它将以静默方式掩盖任何推到C
之上的提交。 --force-with-lease
在这种情况下将中止,这将是不进行历史记录重写的进一步原因(或者如果您继续进行重写,则需要做额外的工作)。
没有历史重写
如果由于某种原因不适合使用历史记录重写,或者如果您只希望使用破坏性较小的解决方案并且可以接受“混乱的”历史记录,那么您可以执行以下操作。 同样,你有
O -- x -- x <--(master)
\
A -- B -- C <--(branch)(origin/master)(origin/branch)
我们需要一个新的提交,使origin/master
的内容与master
保持一致。 为此,我们可以使用git revert
git checkout origin/master
git checkout -b temp
git revert -n master..branch
git commit
这给你
O -- x -- x <-(master)
\
A -- B -- C <--(branch)(origin/master)(origin/branch)
\
~CBA <--(temp)
您可以使用git diff
验证temp
匹配master
。 最终,我们将master
移到temp
,但是在这样做之前,我们应该解决一个新问题:
在这一点上, A
, B
和C
已集成到master
的历史记录中,但是更改未反映在最终状态中(因为它们已还原); 这意味着branch
不能合并回来。解决此问题稍微复杂一点,因为您已将branch
推送到origin/branch
,并且我们不想创建另一个历史记录重写方案。
不过,要解决此问题,我们需要A
, B
和C
新副本。
git rebase --onto temp master branch
将创建副本
O -- x -- x <-(master)
\
A -- B -- C <--(origin/master)(origin/branch)
\
~CBA <--(temp)
\
A' -- B' -- C' <--(branch)
现在,一切都可以通过快进合并和快进推送解决。
git checkout master
git merge temp
git branch -D temp
git push
产量
O -- x -- x -- A -- B -- C <--(origin/branch)
\
~CBA <--(master)(origin/master)
\
A' -- B' -- C' <--(branch)
接着
git checkout branch
git push
产量
O -- x -- x -- A -- B -- C -- ~CBA <--(master)(origin/master)
\
A' -- B' -- C' <--(branch)(origin/branch)
请注意,在这些步骤中,我对推送使用了默认的refspecs。 你可以说
git push origin master
和
git push origin branch
但是IMO过于习惯于指定,因此很容易将其推送到错误的远程分支。 相反,我建议您进行配置设置,以便您大多数时间都可以依赖默认值。
AFAIK只有一种方法,您需要使用正确的分支指针force push
送到原始主机。
因此,在本地您可以将master分支重置为正确的原始/ master状态,然后
git push -f origin HEAD:master
这会将原点上的主指针重置为正确的状态。 在您之间拉/取的任何人都犯了错误,并且您修复了这个错误,应该再次拉/取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.