如何合并两个Git仓库?

2213
考虑以下情况: 我已经在自己的Git repo中开发了一个小型实验项目A。现在它已经成熟,我想让A成为更大的项目B的一部分,B有自己的大型仓库。现在我想将A作为B的子目录添加进去。 如何将A合并到B中,而不会丢失任何一方的历史记录?

17
如果您只是尝试将两个存储库合并为一个,而不需要保留两个存储库,请参考此问题:https://dev59.com/CWcs5IYBdhLWcg3wOBRC - Flimm
27个回答

3

我会手动轻微合并项目,这样我就避免了需要处理合并冲突的情况。

首先,以任何你想要的方式复制其他项目中的文件。

cp -R myotherproject newdirectory
git add newdirectory

历史中的下一次拉取

git fetch path_or_url_to_other_repo
告诉Git合并上次获取的历史记录。
echo 'FETCH_HEAD' > .git/MERGE_HEAD

现在您可以按照通常的方式提交代码。

git commit

1
这是唯一一个有意义的解决方案,而且完全符合我的期望和要求。 - Mike Lyons

3

今天我遇到了以下问题,需要解决:

项目A位于Bitbucket上,项目B位于Code Commit上,它们是相同的项目,但是需要将A中的更改合并到B中。(关键是在项目A中创建与项目B中相同名称的分支)

  • git checkout Project A (切换到项目A)
  • git remote remove origin(删除当前remote)
  • git remote add origin Project B(添加指向项目B的remote)
  • git checkout branch(切换到指定branch)
  • git add *(添加所有修改的文件)
  • git commit -m "we have moved the code"(提交代码)
  • git push(推送到远程仓库)

2

这个函数会将远程仓库克隆到本地仓库目录,合并后所有提交记录将被保存,git log将显示原始的提交记录和正确的路径:

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

如果稍作修改,您甚至可以将合并后的存储库中的文件/目录移动到不同的路径中,例如:

repo="https://github.com/example/example"
path="$(pwd)"

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

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

GIT_ADD_STORED=""

function git-mv-store
{
    from="$(echo "$1" | sed 's/\./\\./')"
    to="$(echo "$2" | sed 's/\./\\./')"

    GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}

# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'

git filter-branch --index-filter '
    git ls-files -s |
    sed "'"$GIT_ADD_STORED"'" |
    GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
    mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD

GIT_ADD_STORED=""

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"

通知
通过sed替换路径,因此在合并后确保它移动到正确的路径。
--allow-unrelated-histories参数仅适用于git版本>= 2.9。


1

给出的命令是我建议的最佳解决方案。

git subtree add --prefix=MY_PROJECT git://github.com/project/my_project.git master

1
除了使用remote add -> fetch -> merge策略的所有答案之外:如果您想保留来自其他存储库的标记,但不想将它们全部溢出到公共命名空间中(可能会发生冲突),您可能需要稍微更改fetch命令:
git fetch --no-tags other_repo
git fetch --no-tags other_repo 'refs/tags/*:refs/tags/other_repo/*'
第一个命令像往常一样获取所有的分支,但省略了附加到提交的标签,第二个命令也省略了通常的标签获取机制(有关更多信息,请参见git help fetch),并使用git的refspec功能将所有标记从X映射到other_repo/X。 引用(分支、标签)只是git中的文件,您可以使用目录进行命名空间。上述两个命令将保留来自第一个存储库的标记,而来自第二个存储库的标记将以other_repo/为前缀。 操作后最好删除其他远程仓库,以免意外地以正常方式获取标签并造成混乱。

0

我想将一个小项目移动到一个大项目的子目录中。由于我的小项目没有太多的提交,所以我使用了git format-patch --output-directory /path/to/patch-dir。然后在大项目中,我使用了git am --directory=dir/in/project /path/to/patch-dir/*

这种方法比filter-branch要简单得多,也更加干净。当然,它可能并不适用于所有情况。


0
注意:这个解决方案可能会推送不需要的LFS二进制文件(这些文件在合并的祖先提交中没有使用),所以你可能需要改进这个解决方案。 为了完成Andresch Serj在这种情况下的好回答,如果项目a使用Git LFS以便能够推送,我首先需要执行以下操作:
cd /path/to/project-a
git lfs fetch --all # some old LFS objects might only be on the server of project-a and not in your clone of project-a

# possible alternative to the following two commands (untested): do a git lfs fetch from path/to/project-b
git remote add project-b-origin url-to-project-b-server
git lfs push --all project-b-origin
在我的情况下,这解决了我在项目-a克隆目录中尝试git push合并结果时遇到的错误。
remote: GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".

并且

Unable to find source for object <hash> (try running `git lfs fetch --all`)
Git LFS upload failed:
    (missing) <path> (<hash>)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,