如何将使用“ git replace”编辑的历史记录推送到远程

Zan*_*zer 2 git version-control merge bitbucket

我有一个具有如下历史记录的遥控器:

在此处输入图片说明

如您所见,O和P是合并提交,并且它们都关闭了它们的旧分支,因此现在只有一个分支。

我想将CDEGJKLN压缩为一次提交,将FHIM压缩为另一次提交,因为它们只是使历史混乱的微小提交。

在本地,我设法使用John O'M的答案所述的方法压缩CDEGJKLN。对于这个问题,像这样:

git checkout -b squashing-1 N
git reset --soft C~
git commit -m "Squashed history"
git replace N [ID_of_the_commit_i_just_made]
Run Code Online (Sandbox Code Playgroud)

并且可以正常工作,git log从主分支本地正确地报告Q,P,O,X,M,I等(X是新压缩的提交)。

从这里开始,下一步是(1)签出主分支并合并更改,(2)删除临时本地分支,然后(3)将更改推送到远程仓库。但是(1)和(3)报告“ 已经更新”或“ 一切都已更新”,因为对树没有任何实际更改,这正是所有这些要点

我也尝试过使用git push --force origin main-branchgit push --force-with-lease origin main-branch但是得到了相同的结果:一切都是最新的。


如何正确合并这些历史记录更改并将其推送到BitBucket,而不必重新创建整个存储库?

tor*_*rek 6

从本质上来说,您可以选择:您是希望让所有人使用替换引用,还是希望重写整个存储库,并使每个人都有很大的忙碌日,在此期间他们从“旧存储库”切换到“新存储库” “?两种方法都不是特别有趣或无利可图。:-)

替代品的工作方式

要做的git replace是在Git存储库中添加一个新对象,并在refs/replace/名称空间中为其命名。该名称空间中的名称是新对象替换的对象的哈希ID。例如,如果您要替换commit 1234567...,则新对象的名称(其ID不是1234567...-具体来说,它的ID不是- fedcba9...而是它的名称)是refs/replace/1234567...

休息的Git,找对象时,首先检查,看是否有一个refs/replace/<hash-id>对象。如果是这样(并且不禁止替换),那么Git的其余部分将返回refs/replace/名称所指向的对象,而不是实际的对象。因此,当Git的其他部分读取某些表示“我的父提交为1234567...”的提交时,Git的另一部分将去查找1234567...,查看refs/replace/1234567...存在的内容并返回对象fedcba9...。然后,您将看到替换项。

但是,如果您没有引用refs/replace/1234567...,则您的Git永远不会交换替换对象。(无论您是否具有替换对象,这都是事实。引用本身会导致替换发生。具有引用保证您拥有对象。)

因此,为了使其他一些Git执行相同的替换过程,您必须refs/replace/引用传递给该其他Git。

将替换从一个Git转移到另一个

通常,您可以使用以下方法推送此类对象:

git push <repository> 'refs/replace/*:refs/replace/*'
Run Code Online (Sandbox Code Playgroud)

(或明确列出您希望推送的一个替换参考)。要获取这些对象:

git fetch <repository> 'refs/replace/*:refs/replace/*'
Run Code Online (Sandbox Code Playgroud)

(您可以将此获取refspec添加到fetch每个克隆中的配置中。使用git fetchgit fetch <repository>将自动拾取推送的任何新替换对象。推送仍然很麻烦,当然,必须在每个新克隆上重复此步骤。)

请注意,此处的refspec均未设置强制标志。如果refs/replace/发生这种情况,是否要强制覆盖现有引用取决于您。

重写存储库

另外,一旦你在地方有替代品,你可以运行一个存储库复制操作由这一点,我的意思是承诺,通过提交副本,而不是快速复制一样git clone --mirror-如git filter-branch。如果在不禁用替换的情况下运行了此复制操作,则不会复制替换的对象;而是复制其替换。因此:

git filter-branch --tag-name-filter cat -- --all
Run Code Online (Sandbox Code Playgroud)

在复制的存储库中永久存在“水泥替换”的副作用。然后,您可以丢弃所有原始引用所有替换引用。(执行此操作的简单方法是克隆已过滤的存储库。)

当然,由于这是一个新的不同的存储库,因此它与原始存储库或其任何克隆都不兼容。但是,它不再需要仔细协调refs/replace/名称空间(因为它不再具有任何替换对象!)。