将两个git分支合为一个

时间:2019-03-14 09:11:45

标签: git

鉴于这种情况

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

我想将BnD1挂钩,即使BnD1完全无关,我们也有一条干净的路。我不需要做任何花哨的合并或以其他方式影响任何实际的源代码,因为D分支完全取代了B分支,我只是想说Bn现在是另一个D1C的父级,即:

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

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

1 个答案:

答案 0 :(得分: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'的父母A并显示。结果是B似乎已经消失了。相同的技巧将适用于您的情况:如果要在只有一个的情况下引入两个父母,则替换一个具有两个父母而不是只有一个的父母。

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

您可以安排克隆它们,但是现在,您可以使用no-no-op 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/名称,使其看起来与建议的克隆替换相同(除了原始对象往往会停留一段时间(基本上,直到垃圾收集器到处清理它们为止)。