将两个git分支合二为一

问题描述 投票:0回答:1

鉴于这种情况

A--B
|  B1
|  B2
|  ...
|  Bn label:b-branch
|
C--D1
|  D2
|  ...
|  Dn label:d-branch
|
E

我想把Bn挂钩到D1所以我们有一个很好的清洁路径,即使BnD1是完全无关的。我不需要做任何花哨的合并或以其他方式影响任何实际的源代码,因为D分支完全取代B分支,我只是想以某种方式说Bn现在是D1的另一个父亲以及C,即:

A--B
|  B1
|  B2
|  ...
|  Bn label:b-branch
|  |  <- Only this link is new
C--D1
|  D2
|  ...
|  Dn label:d-branch
|
E

代码托管在私有GitLab实例上,因此我知道每当我们更改历史记录时,每个人都必须同步。

git
1个回答
2
投票

git replace开始。我不太确定以哪种方式阅读你的图表,所以我只想说你可以用--edit--graft。这将取代一些提交,替换有你喜欢的任何改变。

新的替换实际上不在图中!例如,假设我是以下图表,我们从右侧开始阅读并向左工作以便及时返回:

A <-B <-C <-D <-E   <-- master

提交ED作为其父级,其中C作为其父级,依此类推。

我们可以使用C'创建一个新的提交A,其父级是git replace --graft hash-of-C hash-of-A,给出:

A--B--C--D--E   <-- master
 \
  C'   <-- refs/replace/hash-of-C

git log或其他类似命令走向图形时,它们可能从E开始并显示它,然后移动到D并显示它。接下来发生了棘手的一点:他们转移到C,但此时,他们注意到refs/replace/hash-of-C存在。他们完全放开了C而转而使用C',并表明了这一点。他们移动到C's父母A并表明。结果是B似乎消失了。同样的伎俩适用于你的情况:如果你想引入两个只有一个父母的父母,那你就做了一个有两个父母而不是一个父母的替代品。

这种替换提交的缺点是git clone通常会省略refs/replace/命名空间及其提交。所以克隆存储库的人会看到原始提交 - 他们的Git根本没有refs/replace/hash,并且从不复制替换提交。

你可以安排克隆这些克隆,但是现在你可以使用一个不用操作的git filter-branch来“粘合”新存储库中的替换。例如,之后:

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

在我上面提到的五个提交和替换存储库中,您将拥有:

A--B--C--D--E   <-- refs/original/refs/heads/master
 \
  C'   <-- refs/replace/hash-of-C
    \
     D'-E'  <-- master

通过制作另一个克隆来丢弃refs/original/refs/replace/命名空间名称,最终得到:

A--C'-D'-E'  <-- master

这使嫁接成为永久性的。因此,您现在可以克隆存储库并使用克隆作为替换存储库,或者只是丢弃原始存储库中的refs/replace/refs/original/名称,使其看起来与建议的克隆替换名称相同(除了原始对象倾向于逗留一段时间 - 基本上,直到垃圾收集器到处清理它们。

© www.soinside.com 2019 - 2024. All rights reserved.