2017-02-21 143 views
2

我有一个存储库A(原始存储库),它具有完整的提交集。在某个时间点,决定不再使用存储库A,并且从头开始创建新的清理存储库B,使用复制+粘贴将所有的存储库A的内容(不是将A的内容合并到干净的B中,以便保持提交历史记录)。我现在想实现的目标是在第三个新的清理存储库C中粘贴两个存储库的提交和历史记录(历史记录是非常重要的)。最终目标是存储库C应该包含来自源回收站A和B按时间顺序排列,就好像库B完全没有创建,例如仿佛工作仓库A.已进行Git:将两个存储库合并在一起

所以,目前的情况是:

回购答:提交A1>提交A2> A3提交> ...>犯下

回购B:承诺B1 (= A1 + A2 + A3 + ... + An)的>提交B2(=提交的+ 1)> ...>提交BK

尝试了以下的方法:

git remote add -f A <repo_A_url> 
git merge A/master 
git remote add -f B <repo_B_url> 
git merge B/master 

然后解决的冲突。自从历史以某种方式搞砸以来,部分工作。

然后尝试,我认为最干净的方法 - 合并仅回购一成回购C,然后挑樱桃回购B的提交,从B2 ...... BK。它的工作原理,但樱桃采摘合并提交减慢了合并过程。

我可以复制一个话题,请告诉我,如果我这样做,因为通过爬行通过很多线程,主要看到如何将两个回购增加到第三个,通过将它们放置在最终回购中的不同文件夹中。如果你可以分享最合适的,符合标准的和可靠的方法。

非常感谢。

回答

0

你可以通过一次提交樱桃选择一系列的提交。

$ git merge A/master   # merge A/master into C/master 
$ git cherry-pick B2^..Bk  # cherry-pick all B2 to Bk commits 

或者,你可以rebase。转到C仓库master分行。您可以签一个新的banch(比如说,rebase),那么合并B /主,重订其到A/master

$ git checkout -b rebase origin/master # checkout a new branch with clean C-remote/master history 

$ git merge B/master   # merge B/master into C/master 
$ git rebase A/master   # rebase C/master onto A/master 

如果所有的历史看起来不错,然后通过rebase分支代替master

$ git checkout rebase   # make sure current branch is rebase 
$ git branch -D master   # delete local master branch 

$ git checkout -b master  # create & checkout a new 'master' branch  
$ git push -f orgin master  # update C-remote/master 
3

如果你的历史是非常线性的(即只有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-masternew-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选项的分支和标记命令,将本地参考对齐到最适合您的最终状态的任何远程参考。

+0

目前,我正在你的解决方案,它是最好的,现在,我已经之前采用摘樱桃的方法试过,但正如你所说的,如果有更多的分支机构,将获得更多的参与和我是什么在重组期间看到,经常会遇到合并冲突。它们显然是由于这样一个事实,即rebase正试图将B的合并历史合并到A的顶部来线性化(重新绑定)。如果我不正确,请告诉我。如果是这种情况,是否有可能阻止线性化过程? – Ivan

+0

我会添加一些关于处理多个分支的注意事项;从原来的问题我希望你只是有一个线性的历史和懒惰。 –

+0

尽管我提供的更新可能会有所帮助,但您可能需要等待第二次更新......我认为在某些情况下,这些说明会使参考文献混乱不堪。 –