还原git合并提交类型

还原git合并提交类型,git,Git,在这个问题上,我问GitMergeBranchName和GitMergeBranchName-squash之间有什么区别,它是如何影响项目历史的。现在是后续行动: 将此分支推到远程后,是否可以前后更改此合并提交类型-挤压? 背景故事是,我当然和错误的旗帜合并了,现在是时候清理自己了……简短的回答是否定的,除非通过强制推 为了理解为什么,请考虑一个事实,即Git中的合并词充当动词,合并,也用作形容词或名词:合并提交类型合并或合并合并提交()。 当我们使用动词形式to merge时,我们的意思是结合

在这个问题上,我问GitMergeBranchName和GitMergeBranchName-squash之间有什么区别,它是如何影响项目历史的。现在是后续行动: 将此分支推到远程后,是否可以前后更改此合并提交类型-挤压?
背景故事是,我当然和错误的旗帜合并了,现在是时候清理自己了……

简短的回答是否定的,除非通过强制推

为了理解为什么,请考虑一个事实,即Git中的合并词充当动词,合并,也用作形容词或名词:合并提交类型合并或合并合并提交(

)。 当我们使用动词形式to merge时,我们的意思是结合两组不同的变化,这些变化是关于某个公共基础的。这是执行真正的非快进合并和git合并挤压时git merge的动词形式。因此,在这一步中,这两种行为方式是相同的。到目前为止,我们还不错

但是,一旦git merge或git merge-squash完成了它们的to merge操作,它们将采用两种不同的路径。正常的非压缩合并会进行合并提交,这是一个具有两个父提交ID的提交。通过运行git commit(一种普通的单亲提交),挤压合并(A-squash merge)可以实现,或者更确切地说,让您自己来实现。不管是哪种方式,您都会得到一个提交,但是Git提交的问题是,它是由它的哈希ID唯一标识的,而它的哈希ID是由提交中的每一位信息确定的。对于我们的例子来说至关重要的是,这些信息位包括父散列或多个散列

这意味着,当您或Git进行合并后的动词式提交时,如果是合并提交,则将双亲冻结在提交ID中;如果是正常的非合并提交,则将单亲冻结在提交ID中。与每个Git对象一样,一旦从内容计算出哈希ID,就不能更改哈希ID和内容的配对。如果更改内容,则创建一个新对象,该对象将获得一个新的不同ID

因此,在git推送您所做的提交之前,您可以创建一个新的提交,该提交使用相同的树,但只有一个父级,或者两个父级,无论您第一次没有这样做,因此在存储库中都有真正的合并提交和非真正的合并挤压提交对象。然后,您可以选择其中一个并将其发送到某个远程设备,并要求远程设备设置其自己的名称,例如master或developer或远程设备上的任何名称,以指向该名称

但是现在,您已经将这两个散列ID中的一个发送到远程,并要求它将其名称设置为指向该提交。比如说,为了具体起见,您要求远程用户设置名称M。如果您愿意,您可以先发送另一个哈希ID进行另一个提交,并要求远程用户设置另一个名称,例如N,以指向该另一个哈希ID;那通常是可以的。但是如果您要求远程端将M设置为另一个散列ID,远程端将首先查看其当前的M设置。它将看到使M指向新提交而不是旧提交实际上会丢失旧提交,因为新提交的哈希ID在其祖先中没有旧提交的哈希ID,所以新提交的哈希ID不是当前哈希ID M,新提交的父项或父项M也不是,它们的任何父项M也不是,依此类推

因此,远程将拒绝git push:M作为非快进。要让另一个Git将其M设置为新的散列,丢弃旧的散列,必须向其发送一个强制推送操作。这并不能保证远程服务器会服从,但它会告诉远程服务器您确实希望放弃来自其M的一些提交

这里的危险是:

您可能会放弃先前推送的提交,这是您的意图,以支持更好的新哈希,但可能其他使用该远程设备的人已经获取了您的旧合并,因此现在它已在互联网上传播开来。这给每个人都带来了问题

您可以放弃的不仅仅是您推动的合并。假设Bob在提交上添加了一个提交,Carol在Bob的提交上添加了一个提交。您的强制推送将放弃旧提交而代之以新提交,但它也将放弃构建在旧提交之上的Bob和Carol的提交

如果您确定Bob和Carol不存在,并且没有其他人拥有您以前错误的合并样式提交,那么强制取消该提交并用改进的提交替换它是足够安全的。但如果不是,那毕竟是不安全的。你可以把-force-with-lease选项作为一种选择,但是如果其他人收到了你的错误提交,那么错误提交可能会继续返回,像病毒一样困扰你