将两个git repos合并为一个而不重命名文件

时间:2013-03-18 12:56:27

标签: git merge

我想将两个回购A和B合并到一个共同的回购C. A和B都在根文件夹级别有很多文件,所以我想在repo C的根文件夹中创建文件夹A和B,并将每个原始repo的内容放在匹配的文件夹中。

是否在此过程中不使用git mv而执行此操作?问题是我使用Xcode,遗憾的是它不遵循重命名文件的历史记录,所以我想尽可能避免移动。实际上,我想将每个repo直接合并到其子文件夹中。

3 个答案:

答案 0 :(得分:1)

实现这一目标的方法有很多,而且这个问题的博客帖子和SO答案的数量是其两倍。最简单的解决方案可能是使用git-stitch-repo工具。

另一个选项(我没有尝试过)是遵循这个blog post。但它非常血腥,如果您想要移动到子目录中的点文件,则需要进行一些调整。

答案 1 :(得分:1)

  • Subtree merging - 一个简单的解决方案。将只合并一组文件,同时在不同的前缀(目录)下重定位它们。对这些文件的过去历史不会做任何事情。
  • git-subtree脚本及其add命令。将创建合成历史记录,就像始发代码始终位于指定目录中一样。

答案 2 :(得分:1)

我已经能够通过建立迈克尔建议的blog post来进行合并。原始帖子只负责合并主分支 - 我已经扩展它以从合并的存储库中提取所有分支,因此不会丢失历史记录。

重申一下,我发现了许多其他建议的方法来进行这种合并,但没有一种方法可以保存历史记录而不重命名路径(导致Xcode无法显示历史记录)。

# Init a git repo which will contain the merge of the two repos, each in its own subdirectory
cd ~/dev
mkdir Merged
cd Merged
git init

# Dummy initial commit to create a master branch
git commit --allow-empty -m "Initial commit"

# Clone first repo
cd ..
git clone <RepoA url>
cd RepoA

# Checkout all branches
for remote in `git branch -r | grep -v master `; do git checkout --track $remote ; done

# Prepend subdirectory to all committed files paths in all branches
git filter-branch -f --prune-empty --tree-filter ' mkdir -p .sub;
  find . -mindepth 1 -exec mv {} .sub;
  mv .sub RepoA
  ' -- --glob=refs/heads/*

# Garbage cleanup
git gc --aggressive

# Same steps for second repo
cd ..
git clone <RepoB URL>
cd RepoB

# Checkout all branches  
for remote in `git branch -r | grep -v master `; do git checkout --track $remote ; done

# Prepend subdirectory to all committed files paths in all branches
git filter-branch -f --prune-empty --tree-filter ' mkdir -p .sub;
  find . -mindepth 1 -exec mv {} .sub;
  mv .sub RepoB
  ' -- --glob=refs/heads/*

# Garbage cleanup
git gc --aggressive

# Merge modified repos into unified repo
cd ../Merged
git remote add RepoA ../RepoA
git remote add RepoB ../RepoB
git fetch --all
for remote in `git branch -r`; do git checkout -b $remote --track $remote ; done

# Merge wanted branches (usually master) from each original repo into the master branch of the unified repo
git checkout master
git merge RepoA/master
git merge RepoB/master

# Remove remotes
git remote rm RepoA
git remote rm RepoB

# Garbage cleanup
git gc --aggressive

# All done

# Optionally push into a new empty remote repository
git remote add RepoMerged <Merged Repo URL>
git push --all RepoMerged