如果你的历史是非常线性的(即只有master
在每个A和B),这不会太糟糕。如果有很多分支与之抗衡将获得更多的参与(见下面的更新),但仍这将提供一个起点:
首先,创建你的C回购。
git clone /url/for/repo/A C
cd C
现在的B
git remote add B /url/for/repo/B
git fetch B
获取所有对象现在,我们应该有新的C回购两种历史。变基的B回购承诺到史
git rebase --onto master --root B/master
现在你需要更新master
裁判,也许收拾了一下
git branch -f master
git remote remove B
现在被列为你的origin
遥控器;你可能要么推动它,要么将它作为一个原点去除,这取决于你是否打算让A包含前进的一切。
- UPDATE:好吧,这里的情况有点更多信息你的历史不是线性的,因为它可能永远不会是......首先,让我们专注于拓扑结构,然后一两句话就裁判...
拓扑结构的角度来看,实际上是由三个总体情况:
1)分行和B中合并
因此,让我们假设你有(如果没有,通读这个,但看到情况2),这可以追溯到一个单一的根,你可以移植到A中的单个分支提示(如果没有看到下面的方案3,则返回到此) 。
A1 ---- A2 ---- A3 <--- (master)
\ /
A4 -- A5
---------------------------
B1 ---- B2 ---- B3 <--- (master)
\ /
B4 -- B5
在A中可能有分支,但最终他们已经合并回来,您不必担心它们。在B中也可能有分支,尽管它们被合并回来,但如果rebase试图使它们成线性,它们可能会造成麻烦。
首先创建C并导入两个历史记录,如上所述。 (最后我会建议这个程序略有变化,与参考文献无关......但让我们回到那个。)
现在,你有两种选择。最简单的到目前为止是使用filter-branch
(但它可能很耗时)。找到的提交的哈希值上,你会被移植术(上面注A3)和运行
git filter-branch --parent-filter 'sed "s/^\$/-p xxxxxxxxxx/"' B/master
(其中XXXXXXXXXX是散列值)。
这的确假设你有sed;它可以在Windows上的git bash环境中使用,也可以在任何* nix系统上使用。如果没有,你可以拿出一个等效的过滤器。 (它所做的只是说“如果输入是一个空行,写出'-p',接着是我正在嫁接的散列;否则将输入作为我的输出”)。
如果对于某些原因你不能这么做,或者如果它看起来是一个性能问题,那么你可以尝试计划B:给--preserve-merges
选项rebase
...这将做你想要的很多时间。 但有一些重要的警告。
基本上如果合并推出手动更改 - 要么是因为需要手动解决冲突,或者因为合并与--no-commit
完成,以这种方式引入手动更改 - 然后合并将无法正确通过重订转载甚至用这个选项。
在发生冲突的情况下,底垫应该停止,让你重新申请手册分辨率(您可能能够与原有的合并提交的路径结账(checkout ... -- .
)做的事。但在万一有人使用--no-commit
衍合的甚至不知道什么是错的。
如果你知道这将是一个问题,但可以识别一个或两个问题合并,那么一种选择是重订每个问题合并的父母,然后重做手动合并,然后继续从那个点开始
如果你不知道if/where p roblems将发生,你可以尝试rebase然后运行验证来比较提交。做底垫之前
git checkout master
git tag old-B-master
然后尝试底垫
git rebase --preserve-branches --onto master --root B/master
git tag new-B-master
然后做任何验证的水平似乎是安全给你。 (显然,以最低的diff的old-B-master
对new-B-master
。当我做这样的事情,我写了一个脚本来递归遍历提交的祖先比较提交的提交。偏执?也许吧。)
除非这正好非常,非常顺利,你最好回落到filter-branch
的方法。
2)B中
A1 ---- A2 ---- A3 <--- (master)
\ /
A4 -- A5
---------------------------
B1 ---- B2 <--- (master)
\
B4 -- B5 <--- (branch1)
多个分支提示也许您的乙回购未完全合并。这可能会或可能不会使事情复杂化。如果您使用的是filter-branch
,它可以同时在多个参考文件上工作。您可能不能只说--all
(因为它可能会捕获已存在于A
树中的引用,并且操作最终可能会失败),但是您可以列出B
树中的分支提示。
git filter-branch --parent-filter 'sed "s/^\$/-p xxxxxxxxxx/"' B/master B/branch1
如果你正在尝试使用变基(或者,如果你只是想一个尖裁判工作),你可以创建一个临时章鱼合并。
git checkout B/master
git checkout -b b-entry-point
git merge -s ours B/branch1 B/branch2 ...
生成的合并提交是临时的。 (可以在移植后删除b-entry-point分支。)它仅在B
提交树中提供了一个“入口点”。
3)在一个
A --- Am <-- (master)
\
Ab1 <-- (branch1)
---------------------------------------
B1 ---- B2 <-- (master)
B3 ---- B4 <-- (branch1)
多枝梢所以,如果一个并没有完全摆在首位合并?当你创建回购B时,你是否只有创建单个新提交B === Am
?我是这么猜测的,因为你不得不做一些奇怪的事情,像多个历史树木,以包括Ab1
的表示,如果你想重新合并,你稍后会有点头痛...
如果您确实有多棵树要移植,那么我认为您只需分别处理每棵树。没有太多的事情可以改善这一点。
如果您有多个移植分,但他们后来被重新合并为M
所,那么你可能有单独移植每个M
的父母,然后重新合并为M'
,然后继续嫁接孩子M
转换成M'
。
好,但对于裁判?
现在上述情况良好,但您可能有(除A和/或B之外)您关心的仅限于master
分支的参考。
这是多数民众赞成由filter-branch
更好地处理这些事情之一;事实上,如果我记得正确rebase
将不会重写任何ref,除了分支提示其重定位(甚至不是如果它的远程分支参考)。
特别是如果使用filter-branch
,你可能会发现可以方便地通过克隆B和导入远程参创建C形成A(而不是周围的其他方法,如上所示),这样就可以有filter-branch
重写本地参考文献为您。
即便如此,你会发现你需要搬迁远程裁判的某种组合。可以根据需要使用带有-f
选项的分支和标记命令,将本地参考对齐到最适合您的最终状态的任何远程参考。
目前,我正在你的解决方案,它是最好的,现在,我已经之前采用摘樱桃的方法试过,但正如你所说的,如果有更多的分支机构,将获得更多的参与和我是什么在重组期间看到,经常会遇到合并冲突。它们显然是由于这样一个事实,即rebase正试图将B的合并历史合并到A的顶部来线性化(重新绑定)。如果我不正确,请告诉我。如果是这种情况,是否有可能阻止线性化过程? – Ivan
我会添加一些关于处理多个分支的注意事项;从原来的问题我希望你只是有一个线性的历史和懒惰。 –
尽管我提供的更新可能会有所帮助,但您可能需要等待第二次更新......我认为在某些情况下,这些说明会使参考文献混乱不堪。 –