你如何通过rebase保持分支机构共享相同的历史记录?

时间:2017-12-16 23:58:42

标签: git git-rebase

如果我从这段历史开始:

* 505421e - (HEAD -> stage4) go to stage 4
* 307978f - (stage3) go to stage 3
* d8ab213 - steb b
* 49cbef9 - (stage2) step a
* 6e4a2ed - (stage1) go to stage 1
* 3ca2d7d - do something
* 5ce596d - (stage0) go to stage 0
* 0c8487b - foo
* ccfb7c9 - bar

我执行git rebase -i ccfb7c9以更改foo提交,然后分支stage0–stage3将不再具有与stage4相同的提交历史记录,并且不会拥有已更新foo提交。如何让他们拥有相同的历史?

1 个答案:

答案 0 :(得分:1)

你是对的。不幸的是,Git没有任何东西能够以正确的方式实现这一目标"。 定义"对"有点困难。在这里,虽然我有一个特定的定义 1 并开始编写一个程序来做到这一点。对于所有奇怪的角落案件来说都太难了,我放弃了它。

这里的基本问题是git rebase通过复制提交工作,就像git cherry-pick一样(使用交互式rebase让你在此过程中进行一些额外的更改)。< sup> 2 新副本具有新的,不同的哈希ID。 3 创建副本后,Git重新指向一个分支名称 - 当前的分支,无论你何时启动git rebase - 到最后一次这样复制的提交。

换句话说,在这种情况下,你有Git副本:

  • 0c8487b - foo
  • 5ce596d - (stage0) go to stage 0
  • 3ca2d7d - do something
  • ...
  • 505421e - (HEAD -> stage4) go to stage 4

按此顺序(最早到最晚),一次一个。在第一步,您进行某些更改 - 只要您更改某些内容,它就不重要 - 这样新的提交会获得一些新的,不同的哈希ID,例如{{ 1}}(可能实际上并非如此,但这让我们将其称为&#34;新提交1&#34;)。此新提交的父提交是cccccc1,它是标记为ccfb7c9的提交,因此新历史记录将重新加入旧历史记录。

然后Git复制第二个提交bar,即5ce596d - (stage0) go to stage 0cccccc2的父级是cccccc2,与cccccc1完全不同,强制将其作为不同的提交。 Git继续复制所有八个提交,最后一个提交5ce596d或许;然后Git更改名称cccccc8,以便命名提交stage4

因此,当您现在通过从名称cccccc8找到Git的提交开始查看历史记录时,您会看到 new 历史记录。但是Git没有改变任何其他名称:stage4,例如,仍然标识提交stage3,而307978f仍然标识提交stage0 1}}。因此,如果您从任何那些名称开始查看历史记录,您会看到原始提交系列。

你需要的是让Git将每个标签从其原始哈希移动到新哈希。问题在于识别所有这些事情:应该移动哪些标签? (你可能希望有些人故意保留旧的提交,有些人要移动。)就此而言,哪个提交是正确的新提交?如果在交互式rebase期间,我选择拆分一些提交并合并其他提交,该怎么办?

简单而强力的解决方案是手动强制您想要更改的任何名称,以指向新的提交。运行5ce596d并记下每个名称的新旧提交ID,然后运行:

git log --all --decorate --oneline --graph

你完成了。或者,只需完全删除其中一些分支名称,因为您可以从git branch -f stage0 newhash0 git branch -f stage1 newhash1 git branch -f stage2 newhash2 git branch -f stage3 newhash3 (自动移动)和向后工作开始查找提交。

1 我喜欢的定义涉及构造分支名称,因此名称具有更多的语义而不仅仅是#34;指向提交的原始指针&#34;。这个结构的表单也很难:它应该使用名称层次结构,还是应该有stage4个条目将分支名称分组为&#34;超级分支&#34;?

2 有些git config命令实际上运行git rebase,有些则不运行git cherry-pick。交互式rebase是真正运行git cherry-pick以及git commit --amend和其他棘手项目的案例之一。

3 任何Git对象的哈希ID都严格由其内容决定,所以如果&#34; copy&#34;与相同位的原始位100%相同 - 您使用相同的哈希ID,即,您只需重新使用原始位。但是一旦你做了任何改变,序列中某些提交的哈希ID就会改变,这会强制每个&#34;下游&#34; (child)提交一个不同的哈希ID,它也会改变每个下游提交。