如何附加孤立分支以“按原样”掌握?

时间:2015-10-05 17:21:18

标签: git rebase

在转移使用 git 的过程中,我们采用了解决方案的生产版本并将其作为 master 提交。

然后我们采用了开发版本并制作了一个名为 develop 孤儿分支

(背景:为什么我们在这里有点纠结的是,从开发版本到生产版本没有一个干净的演变。另外,组装所涉及的解决方案的复杂性让我们想要避免报废回购并再次尝试。最后,我们只想将这些版本放入 git 并在 git 中开始清理。)

所以 - 现在我们认为从 master 分支开发版本会更好,而不是将其保留为孤儿分支。

我们如何基本上采用 提交并使其成为 develop 提交但没有任何合并发生?不更改第一个 开发 提交的文件内容?

那就是 - 以某种方式将 开发 移植到其上, as-is ,如果这样做的话感?

1 个答案:

答案 0 :(得分:1)

听起来您想修改提交图而不修改附加到这些提交的任何

如果您了解git如何在内部工作,那么这个陈述会更有意义。这里的关键项目是:

  1. 所有提交都是永久性的,不变的,因为"真名称"提交(或实际上任何git的四个内部对象)是其内容的SHA-1加密校验和。这意味着如果你试图改变任何东西(或者一个失败的磁盘驱动器改变某些东西),git会抱怨一个错误的校验和,因为你在每个对象中看到的并不匹配它的真实名称"更多。

  2. 每次提交都带有"树的SHA-1 ID"充当该提交的源的完整快照的对象。 (树提供文件名和SHA-1"每个文件或目录的真实名称和#34;子目录由另一个树表示。这里的细节不重要。 )

  3. 每次提交还会列出"真实姓名"其父级的SHA-1 ID。因此,给定develop的提示提交,git可以读取该提交并找到其直接父级。阅读那个父母(或那些父母),git找到下一个ID,它为父母读取,等等。该过程在读取" root"提交,这是一个没有父母的人。执行--orphan签出然后进行提交会导致新的根提交,这无疑是如何创建分支的。

  4. 存储在任何给定提交中的这些父ID和树ID被称为"指向" git存储库中的其他对象。 (回购中只有四种类型的对象。我们已经提到了#34;提交""树",另外两个是" blob" - 这是git的方式保存文件和"标记"。树指向blob和子树,"标记"对象用于带注释的标记。)

    因此,您要做的是更改develop分支的根提交,以便它现在具有父提交,特别是可以从{{1}的当前提示访问的某些提交分支。 (也许你想要小费本身,也许你想要master这样的东西:这个细节只对你去做改变很重要。)

    坏消息是因为第1项,你不能做到这一点。

    好消息是,你可以使用三种替代方法中的任何一种进行排序(然后根据需要和期望使移植物永久化)。

    首先,git有一个名为" grafts"的东西。他们的工作效果不是很好,所以git有一个新的更好的东西,称为"替换"。根据你的git vintage,你应该至少有一个,几乎肯定都是。

    这两者都使用相同的一般想法。由于git正在执行其遍历的图形遍历,从提交到父级,您希望在某些时候能够获取git来更改其遍历。使用git grafts,您只需在id为master~100的对象上指定它应该遍历父<X>。这使您可以在当前<Y>上找到根提交,并将其直接移植到develop中的某个提交中。

    这些移植物不会被master复制,并引入其他问题,所以现在git有git replace。这将在存储库中创建一个实际对象,并允许您在使用和不使用替换时检查提交图。要在这种情况下使用它,您可以为root-commit进行替换提交,这与现有的root-commit完全相同,只是它具有您想要的父提交。

    如果您想完全重写历史记录,在一次痛苦的重写步骤后让所有用户都能轻松完成,您可以设置移植物,然后使用git clone来复制和替换移植物。或者,可能稍微容易一点,指定父过滤器(而不是其他过滤器)。有关详细信息,请参阅the git filter-branch documentation;它就是这种情况的一个例子。 (文档表明创建移植物更简单,我认为使用git filter-branch更简单;但无论哪种方式,都有一个方便的例子。)

    请注意,filter-branch copy 每隔&#34;过滤&#34;通过(虚拟)检查提交,然后应用过滤器,然后从结果创建新提交,提交,应用一些更改。在这种情况下,第一个更改是将父ID添加到根提交。第二个更改是一个filter-branch自动执行:使跟随的提交不再是孤立的root-copy指向root-copy。第三个变化与第二个变化相同,依此类推:

    --parent-filter

    此处,提交 A--B--C <-- develop (before filtering) ...--o--o--... <-- master \ A'-B'-C' <-- develop (after filtering) 与提交A'完全相同,只是它具有父ID; AB'完全相同,只是其父级为B而不是A';等等。

    (顺便说一句,请注意,父箭头都指向左侧,但A从左到右工作。它通过枚举所有要首先过滤的提交,将其ID设置为正确来实现此目的。然后从左到右进行过滤。)

    This existing SO Q-and-A has a lot more on using grafts or replace.

    我确实提到了上面的第三种方法。仅当filter-branch没有现有的合并提交时,此方法才有效。然后,您可以简单地将develop中的每个提交重新绑定到目标提交上,如siride suggested in a comment。您需要使用develop运行该rebase命令,以复制来自独立--root分支的根目录的每个提交。

    这是有效的,因为develop只是简单地复制提交,就像git rebase一样。从某种意义上讲,它的工作量更大,因为方式 rebase复制提交是通过应用差异(使用重复的git filter-branch,或多或少)而不是简单地保留每个复制的提交&# 39;现有的&#34;树&#34;对象,但它比git cherry-pick更容易工作。这里的缺点是rebase根本不处理合并提交(好吧,除非你使用git filter-branch,否则使用交互式rebase代码)。