结合多个Git仓库

假设我有一个像这样的设置

phd/code/ phd/figures/ phd/thesis/ 

由于历史原因,这些都有自己的git仓库。 但是我想把它们合并成一个简单的东西。 例如,现在我可能会做两套更改,必须做类似的事情

 cd phd/code git commit cd ../figures git commit 

这只是(现在)很好,只是执行

 cd phd git commit 

似乎有一些使用子模块或从我的子库中取出的方法,但这比我想要的要复杂一些。 至less,我会很高兴的

 cd phd git init git add [[everything that's already in my other repositories]] 

但是这看起来并不像一个class轮。 有没有什么可以帮助我的git

这是我在这里给出的一个解决scheme:

  1. 首先做一个你的phd目录的完整备份:我不想为你失去多年的辛苦工作负责! 😉

     $ cp -r phd phd-backup 
  2. phd/code的内容移动到phd/code/code ,并修改历史logging,使其看起来像它一直在那里(这使用git的filter-branch命令):

     $ cd phd/code $ git filter-branch --index-filter \ 'git ls-files -s | sed "s-\t-&code/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD 
  3. phd/thesis的内容也是一样(只是用figuresthesis代替code )。

    现在你的目录结构应该如下所示:

     phd |_code | |_.git | |_code | |_(your code...) |_figures | |_.git | |_figures | |_(your figures...) |_thesis |_.git |_thesis |_(your thesis...) 
  4. 然后在根目录下创build一个git仓库,把所有东西都放进去,然后删除旧的仓库:

     $ cd phd $ git init $ git pull code $ rm -rf code/code $ rm -rf code/.git $ git pull figures --allow-unrelated-histories $ rm -rf figures/figures $ rm -rf figures/.git $ git pull thesis --allow-unrelated-histories $ rm -rf thesis/thesis $ rm -rf thesis/.git 

    最后,你现在应该有你想要的:

     phd |_.git |_code | |_(your code...) |_figures | |_(your figures...) |_thesis |_(your thesis...) 

这个过程的一个好处就是它将会保留非版本化的文件和目录。

希望这可以帮助。


只是一个警告的话:如果你的code目录已经有一个code子目录或文件,事情可能会非常错误(当然figuresthesis相同)。 如果是这种情况,只需在完成整个过程之前重命名该目录或文件即可:

 $ cd phd/code $ git mv code code-repository-migration $ git commit -m "preparing the code directory for migration" 

当程序完成后,添加最后一步:

 $ cd phd $ git mv code/code-repository-migration code/code $ git commit -m "final step for code directory migration" 

当然,如果code子目录或文件没有版本化,只需使用mv而不是git mv ,而忘记了git commit

git-stitch-repo会在命令行给出的git仓库中处理git-fast-export --all --date-order的输出,并创build一个适合于git-fast-import的stream,它将创build一个新的存储库,其中包含所有提交树中的所有提交,这些提交树尊重所有源存储库的历史logging。

也许,简单地(与前面的答案类似,但使用更简单的命令)在每个单独的旧版本库中创build一个将内容移动到适当命名的子目录中的提交,例如:

 $ cd phd/code $ mkdir code # This won't work literally, because * would also match the new code/ subdir, but you understand what I mean: $ git mv * code/ $ git commit -m "preparing the code directory for migration" 

然后把这三个单独的回购合并成一个新的,做得像下面这样:

 $ cd ../.. $ mkdir phd.all $ cd phd.all $ git init $ git pull ../phd/code ... 

那么你会保存你的历史,但会继续一个回购。

您可以尝试kernel.org上的子树合并策略页面,或者在这里查看镜像 。 它会让你把repo B合并到repo A.与git-filter-branch ,它不需要你重写历史logging(打破SHA1的总和)。

git-filter-branch解决scheme运行良好,但请注意,如果您的git repo来自SVN导入,则可能会失败,并显示以下消息:

 Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory 

在这种情况下,您需要从filter分支中排除最初的修订版 – 即将末尾的HEAD更改为[SHA of 2nd revision]..HEAD – 请参阅:

http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html

@MiniQuark解决scheme对我有很大帮助,但不幸的是,它没有考虑源代码库中的标签(至less在我的情况下)。 以下是我对@MiniQuark答案的改进。

  1. 首先创build将包含合成回购和合并回购的目录,为每个合并的回收创build目录。

    $ mkdir new_phd
    $ mkdir new_phd / code
    $ mkdir new_phd /数字
    $ mkdir new_phd / thesis

  2. 做一个拉库,并获取所有标签。 (仅提供code子目录的说明)

    $ cd new_phd / code
    $ git init
    $ git pull ../../original_phd/code master
    $ git fetch ../../original_phd/code refs / tags / *:refs / tags / *

  3. (这是对MiniQuark答案中的第2点的改进)将new_phd/code的内容移动到new_phd/code/code并在每个标记之前添加code_

    $ git filter-branch –index-filter'git ls-files -s | sed“s- \ t”* – &code / – “| GIT_INDEX_FILE = $ GIT_INDEX_FILE.new git update-index –index-info && mv $ GIT_INDEX_FILE.new $ GIT_INDEX_FILE'–tag-name-filter'sed”s – 。* – code _& – “'HEAD

  4. 这样做之后,会有两倍的标签,因为它是在做分支之前。 旧标签保留在回购中,并添加了带有code_前缀的新标签。

    $ git标签
    是MyTag1
    code_mytag1

    手动删除旧标签:

    $ ls .git / refs / tags / * | grep -v“/ code_”| xargs rm

    对其他子目录重复2,3,4点

  5. 现在我们有@MiniQuark中的点3的目录结构。

  6. 像MiniQuark安装程序的第4点一样,但是在执行pull之后,在删除.git目录之前,取标签:

    $ git fetch catalog refs / tags / *:refs / tags / *

    继续..

这只是另一个解决scheme。 希望它有助于某人,它帮助了我:)

来自Aristotle Pagaltzis的“ git-stitch-repo ”答案只适用于具有简单线性历史的存储库。

MiniQuark的答案适用于所有的存储库,但它不处理标签和分支。

我创build了一个与MiniQuark所描述的程序相同的程序,但它使用了一个合并提交(与N个父代),并重新创build所有标记和分支以指向这些合并提交。

有关如何使用它的示例,请参阅git-merge-repos存储库 。

我已经创build了一个工具来完成这个任务。 使用的方法是类似的(内部做一些像 – 过滤分支),但更友好。 是GPL 2.0

http://github.com/geppo12/GitCombineRepo

你build议的顺序

 git init git add * git commit -a -m "import everything" 

将工作,但你会失去你的承诺历史。

其实,git-stitch-repo现在支持分支和标签,包括带注释的标签(我发现有一个我报告的bug,并且已经修复)。 我发现有用的是标签。 由于标签附加到提交,并且一些解决scheme(如Eric Lee的方法)不能处理标签。 您尝试从导入的标签中创build一个分支,它将撤销任何git合并/移动,并将您发送回来,就像整合存储库与标签来自的库一样。 另外,如果您在“合并/合并”的多个存储库中使用相同的代码,则会出现问题。 例如,如果您有回购的A广告B,都有标签rel_1.0。 您将回购A和回购B合并到回购AB中。 由于rel_1.0标签有两个不同的提交(一个用于A,一个用于B),哪个标签在AB中可见? 要么从导入的回购A的标签,要么从import的回购B,但不是两个。

git-stitch-repo通过创buildrel_1.0-A和rel_1.0-B标签来帮助解决这个问题。 您可能无法检出rel_1.0标签并期待两者,但至less可以看到两者,理论上讲,您可以将它们合并到一个通用的本地分支中,然后在该分支上创build一个rel_1.0标签(假设您只是合并而不是更改源代码)。 与分支机构一起工作会更好,因为您可以像分支机构一样将每个分支机构合并到本地分支机构中。 (dev-a和dev-b可以合并成一个本地dev分支,然后可以推送到原点)。

在mainProject中合并第二个项目:

A)在第二个项目

 git fast-export --all --date-order > /tmp/secondProjectExport 

B)在主项目中:

 git checkout -b secondProject git fast-import --force < /tmp/secondProjectExport 

在这个分支中,你需要做的一切繁重的转变,并提交它们。

C)然后回到主人和两个分支之间的古典合并:

 git checkout master git merge secondProject 

我也会在这里抛出我的解决scheme。 这基本上是一个简单的bash脚本包装git filter-branch 。 像其他解决scheme一样,它只迁移主分支,不迁移标签。 但完整的主提交历史是迁移,这是一个简短的bash脚本,所以用户应该相对容易审查或调整。

https://github.com/Oakleon/git-join-repos