考虑以下场景:

我在自己的Git repo中开发了一个小型实验项目a。它现在已经成熟,我希望A成为更大的项目B的一部分,该项目有自己的大仓库。现在我想将A添加为B的子目录。

我如何将A合并为B,而不丢失任何方面的历史?


当前回答

要在B中合并a:

1) 在项目A中

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

2) 在项目B中

git checkout -b projectA
git fast-import --force < /tmp/ProjectAExport

在这个分支中,执行所有需要执行的操作并提交它们。

C) 然后回到主节点,两个分支之间进行经典合并:

git checkout master
git merge projectA

其他回答

以下是两种可能的解决方案:

子模块

要么将存储库A复制到较大项目B中的单独目录中,要么(也许更好)将存储库B克隆到项目B的子目录中。然后使用git子模块将此存储库设置为存储库B的子模块。

对于松散耦合的存储库来说,这是一个很好的解决方案,存储库a中的开发仍在继续,而开发的主要部分是a中的独立开发。另请参阅GitWiki上的SubmoduleSupport和GitSubmoduleTutorial页面。

子树合并

您可以使用子树合并策略将存储库A合并到项目B的子目录中。Markus Prinz在《子树合并与你》中描述了这一点。

git remote add -f Bproject /path/to/B
git merge -s ours --allow-unrelated-histories --no-commit Bproject/master
git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
git pull -s subtree Bproject master

(选项--Git>=2.9.0需要允许不相关的历史记录。)

或者你可以使用apenwarr(Avery Pennarun)的git子树工具(GitHub上的存储库),例如,在他的博客文章《git子模块的新替代方案:git子树》中宣布了这一点。


我认为在您的情况下(A是大型项目B的一部分),正确的解决方案是使用子树合并。

如果要将项目a合并到项目b中:

cd path/to/project-b
git remote add project-a /path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

摘自:git合并不同的存储库?

这种方法对我来说效果很好,它更短,在我看来更干净。

如果您想将project-a放到子目录中,可以使用gitfilter repo(不建议使用过滤器分支)。在上述命令之前运行以下命令:

cd path/to/project-a
git filter-repo --to-subdirectory-filter project-a

合并两个大型存储库,将其中一个放在子目录中的示例:https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

注意:--allow非相关历史参数仅在git>=2.9之后存在。请参阅Git-Git merge文档/-允许不相关的历史记录

更新:按照@jstadler的建议添加了--tags,以便保留标签。

几天来我一直在尝试做同样的事情,我使用的是git2.7.2。子树不会保留历史。

如果不再使用旧项目,可以使用此方法。

我建议你先在B分支机构工作,然后在该分支机构工作。

以下是没有分支的步骤:

cd B

# You are going to merge A into B, so first move all of B's files into a sub dir
mkdir B

# Move all files to B, till there is nothing in the dir but .git and B
git mv <files> B

git add .

git commit -m "Moving content of project B in preparation for merge from A"


# Now merge A into B
git remote add -f A <A repo url>

git merge A/<branch>

mkdir A

# move all the files into subdir A, excluding .git
git mv <files> A

git commit -m "Moved A into subdir"


# Move B's files back to root    
git mv B/* ./

rm -rf B

git commit -m "Reset B to original state"

git push

如果您现在在分区A中记录任何文件,您将获得完整的历史记录

git log --follow A/<file>

这是帮助我做到这一点的帖子:

http://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/

如果您想单独维护项目,子模块方法是很好的。然而,如果您真的想将两个项目合并到同一个存储库中,那么您还有更多的工作要做。

第一件事是使用gitfilter分支将第二个存储库中所有内容的名称重写到您希望它们结束的子目录中。因此,您将使用projb/foo.c和projb/bar.html代替foo.c和bar.html。

然后,您应该能够执行以下操作:

git remote add projb [wherever]
git pull projb

git pull将执行git fetch,然后执行git merge。如果您要拉到的存储库还没有projb/目录,那么应该不会有冲突。

进一步搜索表明,在将gitk合并为git时也做了类似的操作。Junio C Hamano在这里写道:http://www.mail-archive.com/git@vger.kernel.org/msg03395.html

与@Smar类似,但使用在PRIMARY和SECONDARY中设置的文件系统路径:

PRIMARY=~/Code/project1
SECONDARY=~/Code/project2
cd $PRIMARY
git remote add test $SECONDARY && git fetch test
git merge test/master

然后手动合并。

(改编自阿纳尔·马纳福夫的帖子)