将其他存储库合并到子目录后修复损坏的 git 历史记录

RaB*_*RaB 5 git merge git-filter-branch git-subtree

我有以下 git 存储库

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

我合并成

  • repoAll,其中每个存储库都被移动到子目录中

所以这看起来像

  • 回购全部
    • 迪拉
    • 目录
    • 目录

我已按照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"
...
Run Code Online (Sandbox Code Playgroud)

但是现在文件的历史记录不再连接了

git log --follow dirA/pom.xml
Run Code Online (Sandbox Code Playgroud)

什么也没显示。

然而,

git log --follow pom.xml
Run Code Online (Sandbox Code Playgroud)

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

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

我考虑过插入一个提交,该提交将在 repoAll 上的初始合并之前进行移动,但这需要我对所有更改(现在是 100+)进行变基并解决更改。

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

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

RaB*_*RaB 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"
    
    Run Code Online (Sandbox Code Playgroud)

    对每个存储库重复此操作

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

    cd repoAllNew
    git remote add -f origin-repoA ../repoA
    git pull origin-repoA master
    
    Run Code Online (Sandbox Code Playgroud)

    对每个存储库重复

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

    git blame dirA/src/main/java/HelloWorld.java
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    git remote add -f origin-repoAllOld ../repoAll
    
    Run Code Online (Sandbox Code Playgroud)

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

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

管理总结

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