git - 如何将使用 'git replace'编辑的历史推送到远程

标签 git version-control merge bitbucket

我有一个 Remote ,其历史记录如下:

enter image description here

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

我想将 C-D-E-G-J-K-L-N 压缩到一个提交中,将 F-H-I-M 压缩到另一个提交中,因为它们只是扰乱历史的微小提交。

在本地,我使用 the answer by John O'M. to this question 中描述的方法成功压缩了 C-D-E-G-J-K-L-N。 ,像这样:

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]

这有效,来自主分支的本地 git log 正确报告 Q、P、O、X、M、I 等(X 是新的压缩提交)。

接下来的步骤是 (1) 检查主分支并 merge 更改,(2) 删除临时本地分支,然后 (3) 将更改推送到远程仓库。但是 (1) 和 (3) 报告Already up to dateEverything is up to date 因为树没有实际变化这正是这一切

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


我如何才能正确 merge 这些历史更改并将它们推送到 BitBucket 而无需重新创建整个存储库?

最佳答案

您基本上可以做出选择:您是想让每个人都使用替换引用,还是更愿意重写整个存储库并让每个人都有一个重要的标志日,在此期间他们从“旧存储库”切换到“新存储库”?这两种方法都不是特别有趣或有利可图。 :-)

替换的工作原理

git replace 所做的是将一个新对象添加到 Git 存储库中,并在 refs/replace/ 命名空间中为其命名。此 namespace 中的名称是新对象替换的对象的哈希 ID。例如,如果您要替换提交 1234567... ,则新对象的名称(其 ID 不是 1234567... — 为了具体起见,假设它是 fedcba9...)是 refs/replace/1234567...

Git的rest,在寻找对象的时候,首先检查是否有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

一般来说,你会推送这样的对象:

git push <repository> 'refs/replace/*:refs/replace/*'

(或具体列出您希望推送的替换引用)。要获取这些对象:

git fetch <repository> 'refs/replace/*:refs/replace/*'

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

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

重写存储库

或者,一旦替换到位,您就可以运行存储库复制操作——我指的是逐个提交的复制,而不是像 git clone --mirror 那样的快速复制——比如 git filter-branch 。如果在没有禁用替换的情况下运行此复制操作,则被替换的对象不会被复制;相反,它们的替换被复制。因此:

git filter-branch --tag-name-filter cat -- --all

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

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

关于git - 如何将使用 'git replace'编辑的历史推送到远程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44028493/

相关文章:

git - 如何列出所有曾经在 Git 中提交过文件的人?

svn - 什么构成有效的 SCM 消息?

r - Git 与 RStudio 的本地替代方案?

git rebase 困惑

git - Jenkins MultiBranch - 从管道文件 (Jenkinsfile) 中引用 git repo 的标签

git - 如何将我的 git 存储库的根向上移动一级? (不移动子文件夹)

svn - 如何显示来自 subversion 服务器的存储库列表

java - 创建 pdf 并与 pdfbox 合并

python - Pandas 完整外部索引与 NaN 连接以处理不匹配的索引

Mercurial:如何推送一个书签变更集,它创建一个新的远程头,就像我在推送一个新分支一样?