结合多个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:
-
首先做一个你的phd目录的完整备份:我不想为你失去多年的辛苦工作负责! 😉
$ cp -r phd phd-backup
-
将
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
-
phd/thesis
的内容也是一样(只是用figures
和thesis
代替code
)。现在你的目录结构应该如下所示:
phd |_code | |_.git | |_code | |_(your code...) |_figures | |_.git | |_figures | |_(your figures...) |_thesis |_.git |_thesis |_(your thesis...)
-
然后在根目录下创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
子目录或文件,事情可能会非常错误(当然figures
和thesis
相同)。 如果是这种情况,只需在完成整个过程之前重命名该目录或文件即可:
$ 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答案的改进。
-
首先创build将包含合成回购和合并回购的目录,为每个合并的回收创build目录。
$ mkdir new_phd
$ mkdir new_phd / code
$ mkdir new_phd /数字
$ mkdir new_phd / thesis -
做一个拉库,并获取所有标签。 (仅提供
code
子目录的说明)$ cd new_phd / code
$ git init
$ git pull ../../original_phd/code master
$ git fetch ../../original_phd/code refs / tags / *:refs / tags / * -
(这是对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
-
这样做之后,会有两倍的标签,因为它是在做分支之前。 旧标签保留在回购中,并添加了带有
code_
前缀的新标签。$ git标签
是MyTag1
code_mytag1手动删除旧标签:
$ ls .git / refs / tags / * | grep -v“/ code_”| xargs rm
对其他子目录重复2,3,4点
-
现在我们有@MiniQuark中的点3的目录结构。
-
像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
你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脚本,所以用户应该相对容易审查或调整。