git - 错误合并后如何恢复到远程的旧提交?
问题描述
我使用 BitBucket 作为我的远程仓库。我的一位培训团队成员错误地将另一个分支推入master
. 现在,这就是我的仓库的样子。
好吧,他把事情搞得一团糟。我想将此恢复为4f9ff
具有“添加了新模型类”消息的提交。在我的电脑中,最后一次提交master
也是4f9ff
。
仅供参考,这就是我的本地仓库的样子。
如何将远程仓库恢复为提交4f9ff
?
我试过git push --force origin 4f9ff27:master;
了,它在远程什么也没做。
解决方案
您可以使用git push --force
您尝试过的命令,但您需要稍有不同:
git push --force origin 4f9ff27:master
(您尝试过的)必须改为阅读:
git push --force origin 4f9ff27:refs/heads/master
但是您可以更简单地运行:
git push --force origin master
在你这样做之前,请继续阅读。请注意,Bitbucket 服务器可能仍然拒绝执行此操作,这也取决于您授予自己的权限。
首先,Git 真的是关于提交。这些哈希 ID,无论是缩写(如4f9ff27
)还是完整拼写(完整拼写为 40 个字符),都是提交的“真实名称”。这些“真实姓名”在每个Git 存储库中都有效,只要 Git 存储库确实有 commit。
这些大而丑陋的哈希 ID 的问题在于它们对人类毫无用处。我们不会去记住今天4f9ff27
最新的master
提交,然后明天记住fadbabe
最新的提交,然后在星期二记住现在dadcafe
或其他什么。我们只想说master
并获得最新的提交master
,不管是什么。
这就是分支名称的含义和对我们的作用。每个克隆中的名称 master
(每个都有自己的名称)是 上的“最新提交” 。有你的克隆,在你的笔记本电脑上,有你的,你的团队成员的克隆,在他的笔记本电脑上,有他的——他几乎可以肯定使用的是他的最新版本——Bitbucket 上有一个。master
master
master
4af43...
Bitbucket 上的 Git 存储库在任何方面都没有什么特别之处,除了一个:你和这个人,也许还有更多的人,认为它很特别。但实际上,您自己的每个 Git 存储库都与 Bitbucket 上的一样好,甚至可能更好,因为其中包含您的提交。Bitbucket 之所以特别,只是因为您是这样想的。
所以,当你这样想的时候要小心。请记住,您的提交是您的,您的分支名称是您的,您自己的 Git 存储库是它自己的东西。
当您运行git push
、git fetch
和/或时,您所做git pull
的是连接您的 Git 软件,将您的 Git 存储库与另一个 Git-software-and-repository 对一起使用。将您的 Git(您的软件和存储库作为一对)连接到他们的 Git 后,您现在可以:
- 给他们你所做的任何新的承诺,但他们没有;和
- 要求他们设置一些分支名称。
这是一个git push
操作。
或者,您可以:
- 从他们那里获得他们拥有的任何你没有的新提交。
这是一个git fetch
操作。这不会设置您的任何分支名称,因为git fetch
永远不会触及您的任何分支。
不更新任何分支名称的坏处是......好吧,名称是我们找到提交的方式,因为我们(人类)不擅长随机看起来像4f9ff27
. 因此,当从他们git fetch
那里获得提交时,您的 Git 将复制他们的分支名称,但会更改它们。您将获得远程跟踪名称。如果他们有,并且您调用他们的 Git ,您的 Git 将创建或更新您自己的。master
origin
origin/master
换句话说,这里有点不对称。 当您使用 时,您会从git fetch
它们那里获得新的提交,然后您的 Git 会创建或更新远程跟踪名称。这不会以任何方式干扰任何分支名称。(您从 Bitbucket 获得的新提交可能是因为有人使用了,所以它们可能是由几个不同的人提交的。)git push
但是,当您使用时,您git push
将新提交发送给他们,然后您要求他们(Bitbucket)创建或更新他们的分支名称之一。
分支名称以refs/heads/
通常,你会这样做:
git push origin master
或者:
git push origin feature/xyz
管他呢。此git push
请求使用您身边的分支名称— <code>master 或—来查找要发送的提交。然后你的 Git 将这些提交发送到 Bitbucket。(在这个阶段,他们有机会直接拒绝提交。我不使用 Bitbucket,但值得注意的是,如果任何一个提交中的任何一个文件超过 100 MB,GitHub 将在此时拒绝传入的提交。大多数情况下不过,这还没有真正影响任何事情。)然后——一旦提交完成——你的 Git 会说:现在,如果可以,请将你的名字 _______(填写名称)设置为 ______(填写哈希 ID)。你的 Git 在这里发送的名称是feature/xyz
您用于选择要发送的提交的相同分支名称。
在 Git 内部,分支名称以refs/heads/
. 这意味着你master
是真的refs/heads/master
。 远程跟踪名称,例如origin/master
开头refs/remotes/
,所以origin/master
真的是refs/remotes/origin/master
. 标签名称存在于 中refs/tags/
,例如refs/tags/v2.1
. 大多数情况下,您不必考虑这一点,因为您只需在自己身边使用分支或标签名称 for git push
,而根本不使用任何东西 for git fetch
。对于 fetch 情况,Git在两边使用相同的名称。
但是,当您使用冒号语法4f9ff27:<name>
时,您是在告诉您的 Git:使用左侧的内容来查找要发送/推送的提交,但要求他们在右侧设置名称。当你这样做时,你必须拼出全名。所以这就是4f9ff27:master
不够的原因。
当他们收到这个表格的礼貌请求时,如果可以,请设置一个分支名称,他们会检查它是否可以。如果以下情况在普通 Git 中是可以的:
- 这是一个新分支,或者
- 它只会导致新提交在该分支上变得可查找。
当您需要使用git push --force
或git push --force-with-lease
类似时,这是因为您的非强制推送未通过第二次测试:您正在告诉另一个 Git 设置分支名称,以使某些提交无法找到在他们的存储库中使用您告诉他们设置的分支名称。
在你这样做之前,如果这些提交是有价值的,那么确保有人仍然可以找到它们是个好主意。谁能找到它们 并不重要,但需要有人能够做到这一点。
如果所有这些提交肯定可以通过其他分支名称找到,那么您就可以开始了,并且可以继续使用git push --force master
. 如果没有,您应该确保其他人保留他的提交,和/或在 Bitbucket 存储库中设置一些其他分支名称,以便 Bitbucket Git 将在其他分支名称下记住这些提交。例如,您可以运行:
git fetch origin
git push origin origin/master:refs/heads/bob
使(Bitbucket)refs/heads/bob
上的名称origin
记住他们master
在您git fetch
运行时拥有的提交哈希 ID。1 现在你可以git push --force-with-lease origin master
。2
1您在此处git fetch
运行时的短语是经过深思熟虑的:如果有人积极推送到 Bitbucket,您git fetch
将获得git fetch
运行时的提交。有可能几秒甚至几毫秒之后,有人添加了十个新的提交。你还没有它们!有很多方法可以解决这个问题,但在较小的商店中,有时有人会大喊(和/或在 Slack 上发帖)“不要推动掌握,我们正在修复它”,然后几分钟后“都修好了,你可以再推”。
2该--force-with-lease
选项是--force
. Plain--force
对 Bitbucket Git 说:立即设置!refs/heads/master
4f9ff27
--force-with-lease
选项说: 我认为你refs/heads/master
是 ______(通过 origin/master 填空);如果是这样,请将其设置为4f9ff27
现在! 这处理了我在脚注 1 中提到的那场比赛:如果有人推了,你有机会再试一次。
一个简短的关于git pull
很多人喜欢用 来git pull
作为 的反义词git push
,但它不是(相反,即)。这git fetch
是一个接近对立面的人。
什么git pull
是:
- 运行
git fetch
;然后 - 运行第二个 Git 命令。
第二个命令通常是,git merge
尽管您可以让它运行git rebase
,即使默认情况下也是如此。第二个命令的要点很简单:git fetch
永远不会影响您的任何分支,但通常,您运行的原因git fetch
是为了影响您的某些分支。这需要额外的命令。
将 fetch 和一个附加命令拉在一起。如果您想要或需要多个命令(我经常这样做)或不需要fetch
其他命令,那么首先运行,然后运行命令(复数)或不执行任何操作更有意义。在这种情况下,您不希望您的 Git 更新您的 master
. 你希望你的 Git 让你master
一个人呆着。所以你想要git fetch
,不是git pull
。
受保护的分支
Git,在它的基础上,没有分支保护。托管 GitHub、GitLab 和 Bitbucket 等网站增加了受保护分支的想法。
受保护的分支限制谁可以使用分支名称做什么。确切的细节取决于托管服务。查看 Bitbucket 为该名称提供的保护master
。您可能能够阻止除您自己之外的任何人直接向它推送。您可能可以阻止包括您自己在内的任何人直接推送到它,即使使用--force
,所以要小心这些设置,但如果您是管理员,即使您不小心已经删除了自己的权限,您也应该能够授予自己权限.
结论
您尝试做的强制推动大部分是正确的。确保其他人的提交不会完全丢失——例如,将它们保存在您自己的笔记本电脑上,git fetch
并使用您自己的分支名称,和/或在适当的情况下在 Bitbucket 上创建另一个分支。如果您确定其他提交可通过其他分支名称获得(即,其他人没有进行合并然后删除),则可以跳过此步骤。
然后,一旦你确定它是安全的,git push --force
。如果您已禁止 Bitbucket 允许任何强制推送,即使是您自己,请允许自己强制推送至少足够长的时间以完成此操作。
推荐阅读
- java - 如何使用 spark Java API 将具有科学格式的双精度转换为字符串?
- php - Composer 更新正在尝试删除根包
- r - 如何使用闪亮和 gridExtra 进行绘图?
- autodesk-forge - 如何使用 VertexBufferReader 访问特定的零件几何图形
- c# - Wacom API,标签上的 TextAlign 不起作用
- prestashop-1.6 - 如何在 prestashop 中获取管理文件夹的名称?
- ios - ios JSON 映射对象
- c++ - 如何在 Visual Studio 2013 中将多个点云库源文件与 CMAKE 一起使用?
- r - 有条件地替换R中前几行中的值
- mysql - SQL 数据插入列错误