I need to merge two Git repositories into a brand new, third repository. I've found many descriptions of how to do this using a subtree merge (for example Jakub Narębski's answer on How do you merge two Git repositories?) and following those instructions mostly works, except that when I commit the subtree merge all of the files from the old repositories are recorded as new added files. I can see the commit history from the old repositories when I do git log, but if I do git log <file> it shows only one commit for that file - the subtree merge. Judging from the comments on the above answer, I'm not alone in seeing this problem but I've found no published solutions for it.

有没有办法合并存储库,并保持单个文件历史完整?


当前回答

我根据x-yuri的答案创建了一个库,其中使用了filter-repo。使用我的脚本,您可以轻松地将所有分支和标记移动到新的存储库中,而不会因为指定不同的子dirs而发生合并冲突。

其他回答

这是一种不重写任何历史记录的方法,因此所有提交id都将保持有效。最终结果是第二个repo的文件将在子目录中结束。

Add the second repo as a remote: cd firstgitrepo/ git remote add secondrepo username@servername:andsoon Make sure that you've downloaded all of the secondrepo's commits: git fetch secondrepo Create a local branch from the second repo's branch: git branch branchfromsecondrepo secondrepo/master Move all its files into a subdirectory: git checkout branchfromsecondrepo mkdir subdir/ git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} subdir/ git commit -m "Moved files to subdir/" Merge the second branch into the first repo's master branch: git checkout master git merge --allow-unrelated-histories branchfromsecondrepo

您的存储库将有多个根提交,但这不会造成问题。

按照以下步骤,将一个repo嵌入到另一个repo中,通过合并两个git历史,从而拥有一个git历史。

克隆你想合并的两个回购。

Git克隆git@github.com:user/parent-repo.git Git克隆git@github.com:user/child-repo.git

转到child repo

cd child-repo /

运行以下命令,将路径my/new/subdir(3次出现)替换为您想要拥有子repo的目录结构。

Git filter-branch - pruneempty -tree filter ' 如果[!-e my/new/subdir];然后 Mkdir -p my/new/subdir git ls-tree——name-only $GIT_COMMIT | xargs -I files mv files my/new/subdir fi '

去父回购

cd . . / parent-repo /

为父repo添加一个远程,指向子repo的路径

Git远程添加child-remote ../child-repo/

取回子repo

Git获取子远程

合并历史

Git merge -allow-unrelated- history - child-remote/master

如果你现在检查父repo中的git日志,它应该已经合并了子repo提交。您还可以看到来自提交源的标记。

下面的文章帮助我将一个回购嵌入到另一个回购中,通过合并两个git历史,拥有一个单一的git历史。

http://ericlathrop.com/2014/01/combining-git-repositories/

希望这能有所帮助。 编码快乐!

该函数将远程回购克隆到本地回购目录:

function git-add-repo
{
    repo="$1"
    dir="$(echo "$2" | sed 's/\/$//')"
    path="$(pwd)"

    tmp="$(mktemp -d)"
    remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"

    git clone "$repo" "$tmp"
    cd "$tmp"

    git filter-branch --index-filter '
        git ls-files -s |
        sed "s,\t,&'"$dir"'/," |
        GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    ' HEAD

    cd "$path"
    git remote add -f "$remote" "file://$tmp/.git"
    git pull "$remote/master"
    git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
    git remote remove "$remote"
    rm -rf "$tmp"
}

使用方法:

cd current/package
git-add-repo https://github.com/example/example dir/to/save

通知。这个脚本可以重写提交,但会保存所有作者和日期,这意味着新的提交将有另一个哈希值,如果你试图将更改推到远程服务器,它只能用强制键,也会重写服务器上的提交。所以请在启动前进行备份。

利润!

我根据x-yuri的答案创建了一个库,其中使用了filter-repo。使用我的脚本,您可以轻松地将所有分支和标记移动到新的存储库中,而不会因为指定不同的子dirs而发生合并冲突。

假设你想要合并存储库a到b(我假设它们位于彼此旁边):

cd b
git remote add a ../a
git fetch a
git merge --allow-unrelated-histories a/master
git remote remove a

如果你想把a放到子目录中,在上面的命令之前执行以下命令:

cd a
git filter-repo --to-subdirectory-filter a
cd ..

为此你需要安装git-filter-repo(不建议使用filter-branch)。

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

这里有更多。