4

我有以下 git 存储库

  • 回购协议
  • 回购B
  • 回购协议

我结合成

  • repoAll 将每个 repo 移到子目录中

所以这看起来像

  • 回购全部
    • 目录
    • 目录
    • 目录

我已按照http://jasonkarns.com/blog/merge-two-git-repositories-into-one/上的说明进行操作。这基本上意味着

git remote add -f repoA /path/to/repoA
git merge -s ours --no-commit repoA/master
git read-tree --prefix=dirA/ -u repoA/master
git ci -m "merging repoA into dirA"
...

所以现在但是文件的历史不再连接,因为

git log --follow dirA/pom.xml

什么都不显示。

然而,

git log --follow pom.xml

确实显示了该文件的正确(旧)历史记录。这还不够好,因为没有像 eclipse 或其他 git 客户端这样的工具能够显示完整的历史记录。

更糟糕的是,在合并的 repo 上已经有新的提交,因此再次进行合并并不是一个真正的选择(我现在知道我应该在进行合并之前repoA/*进入)。repoA/dirA

我曾考虑过在 repoAll 的初始合并之前插入一个提交,但这将需要我重新调整所有更改(现在是 100+)并解决更改。

问题/解决方案Git 日志在执行读取树合并后显示很少如何重写历史记录以便所有文件(除了我已经移动的文件)都在子目录中?似乎只适用于整个存储库,而不适用于特定的子目录(或者至少如果你已经在 repoAll 上有新的提交)。

我认为应该有某种方法来重写特定子目录(例如 dirA)的历史,但我似乎无法弄清楚如何。

4

2 回答 2

2

基于r3m0t重写历史的想法,以下几行为我完成了整个技巧,将另一个 git 存储库作为新分支合并到我现有的一个子目录中:

(在工作中git-sh我可以省略命令的前导“git”)

co -b my-new-branch 
remote add -f origin-my-old-standalone-project ../my-old-standalone-project/
pull origin-my-old-standalone-project master
mkdir my-new-subdir
ci -am "merge 'old' standalone project as new branch 'my-new-branch'"
git filter-branch --index-filter \
        'git ls-files -s | sed "s%\t\"*%&my-new-subdir/%" |
                GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                        git update-index --index-info &&
         mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD

之后我拥有了两个:新子目录中的单个文件的历史记录,好像它们一直在那里,以及主目录中的正常历史记录,好像子目录中的新文件一直在那里。(如您所见,不需要读取树或任何其他非日常使用的命令,'filter-branch' 完成了整个操作。)IDE 能够(分别;应该;成功测试 PyCharm)与结果。

之后,您应该能够像往常一样合并您的分支,将所有项目合二为一。

tl; dr: --follow按预期工作,正常历史记录,在执行上述 6 条命令将旧 git 项目合并到其他 git 项目的新分支和子目录后

于 2015-03-07T12:06:08.227 回答
2

我最终用一个稍微费力的解决方案解决了这个问题,但它可能更简单

  1. 我记录了开发人员在 repoAll 上第一次提交的 SHA1(因此是加入存储库后的第一次真正提交)。理想情况下,您创建一个分支以便能够再次找到它 ( git branch changes_start_here <SHA1>)
  2. 我再次从一个空存储库开始,并重新克隆了各个存储库(repoA,...)
  3. 我去了 repoA 并添加了一个提交,我将 repoA 的所有内容移动到 dirA 中(仍在 repoA 上)

    cd repoA
    mkdir dirA
    git mv src pom.xml other* dirA  (i.e. all contents except for dirA will be moved to dirA)
    git commit -m "moved repoA to dirA"
    

    对每个回购重复此操作

  4. 在新的(空的组合存储库)repoAllNew 上,我现在将所有本地存储库副本添加为远程

    cd repoAllNew
    git remote add -f origin-repoA ../repoA
    git pull origin-repoA master
    

    重复每个回购

  5. 通过执行类似的操作确保历史记录正常

    git blame dirA/src/main/java/HelloWorld.java
    

    (显然,这必须是具有更长历史的现有文件)。检查责备是否包含每个源代码行的有意义的消息。

  6. 重新导入合并存储库后开发人员所做的所有更改。这可以通过将旧的 repoA 添加为远程来完成:

    git remote add -f origin-repoAllOld ../repoAll
    

    现在我们需要将在加入 repos 后所做的所有新更改合并到清理的存储库中。

    git branch start <SHA1 of origin-repoAllOld/changes_start_here>
    git branch end <SHA1 of origin-repoAllOld/master>
    git rebase --onto master start end
    
  7. 现在您应该拥有与 repoA 相同的状态,但具有正确的历史记录。

管理总结

在开始 repo 迁移之前,我们必须插入一个更改,将每个存储库的内容移动到相应的子目录中。这样,历史仍然是正确的,并且诸如责备之类的事情也可以正常工作。恕我直言,除非你想开始搞乱(在 99% 的情况下你不想这样做),git read-tree --prefix ...否则应该避免使用恕我直言。git filter-branch

于 2013-10-16T11:35:07.937 回答