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.

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


当前回答

假设你想要合并存储库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

这里有更多。

其他回答

这是一种不重写任何历史记录的方法,因此所有提交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

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

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

几年过去了,有一些基于良好的解决方案,但我想分享我的解决方案,因为它有点不同,因为我想将两个远程存储库合并成一个新的存储库,而不删除以前存储库的历史。

Create a new repository in Github. Download the newly created repo and add the old remote repository. git clone https://github.com/alexbr9007/Test.git cd Test git remote add OldRepo https://github.com/alexbr9007/Django-React.git git remote -v Fetch for all the files from the old repo so a new branch gets created. git fetch OldRepo git branch -a In the master branch, do a merge to combine the old repo with the newly created one. git merge remotes/OldRepo/master --allow-unrelated-histories Create a new folder to store all the new created content that was added from the OldRepo and move its files into this new folder. Lastly, you can upload the files from the combined repos and safely delete the OldRepo from GitHub.

希望这可以对任何处理合并远程存储库的人有用。

我把解决方案从@Flimm this变成了一个git别名,就像这样(添加到我的~/.gitconfig):

[alias]
 mergeRepo = "!mergeRepo() { \
  [ $# -ne 3 ] && echo \"Three parameters required, <remote URI> <new branch> <new dir>\" && exit 1; \
  git remote add newRepo $1; \
  git fetch newRepo; \
  git branch \"$2\" newRepo/master; \
  git checkout \"$2\"; \
  mkdir -vp \"${GIT_PREFIX}$3\"; \
  git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} \"${GIT_PREFIX}$3\"/; \
  git commit -m \"Moved files to '${GIT_PREFIX}$3'\"; \
  git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames \"$2\"; \
  git branch -D \"$2\"; git remote remove newRepo; \
}; \
mergeRepo"

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

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

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

利润!