鉴于这种情况
A--B
| B1
| B2
| ...
| Bn label:b-branch
|
C--D1
| D2
| ...
| Dn label:d-branch
|
E
我想将Bn
与D1
挂钩,即使Bn
和D1
完全无关,我们也有一条干净的路。我不需要做任何花哨的合并或以其他方式影响任何实际的源代码,因为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实例上,因此我知道在更改历史记录时每个人都必须同步。
答案 0 :(得分:2)
从git replace
开始。我不太确定该采用哪种方式读取图形,因此我只能说您可以将其与--edit
或--graft
一起使用。这将代替某些提交,并且替换具有您想要的任何更改。
新的替换项实际上不是在图中!例如,假设我有以下图表,我们从右侧开始向左工作以返回到时间,以进行阅读:
A <-B <-C <-D <-E <-- master
提交E
以D
作为其父,以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/
名称,使其看起来与建议的克隆替换相同(除了原始对象往往会停留一段时间(基本上,直到垃圾收集器到处清理它们为止)。