2013-05-05 118 views
1

我们有一个存储库,其中两个目录已在两年前提取为子模块。在保留历史的情况下合并Git子模块

由于git子模块导致太多头痛,因此决定将提取恢复为子模块并将目录返回到父存储库。

现在的问题是,这样做的最佳方式是什么 - 同时保留所有历史记录

我在考虑将子模块添加为远程,然后再添加所有更改。但为此,我需要告诉git它不应该将提交的路径相对于当前目录而不是父目录的根目录进行处理。

难道没有办法用cherry-pick或其他任何聪明的方式吗?

非常感谢!

回答

1

您可以使用git filter-branch,使用手册页中的示例或略微修改的版本in this answer来执行此操作。这是混帐v1.8.2的男人页面版本:

To move the whole tree into a subdirectory, or remove it from there: 

git filter-branch --index-filter \ 
    'git ls-files -s | sed "s-\t\"*-&newsubdir/-" | 
     GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ 
     git update-index --index-info && 
     mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD 

首先,添加每个子模块在父回购远程,然后结帐每个master分支作为本地跟踪分支(如​​3210,submoduleB-master等)。 Git会发出警告,因为分支机构不会共享历史记录,但会以其他方式让您继续。将子模块分支的历史记录重写到适当的子目录中,并将其合并到父代的master中。最后,您将为这些子目录进行一系列合并提交,并在父回购中提供具有凝聚力的单一历史记录。

这听起来要复杂得多。万一出现问题,请务必做好备份。脚本整个事情,所以你可以尝试,直到你做对了。每个子模块的粗略执行顺序如下:

git remote add submodule submodule_remote 
git checkout -b submodule-master submodule/master 
git filter-branch ...  # With the index-filter described above. 
           # Depending on length of history, this could 
           # take quite a while to process/ 
git checkout master   # Get back on parent's master. 

现在您面临着一个选择。您是否重写父级以删除子模块的所有痕迹,或者不是?如果是后者,请使用适合您的git version,然后git merge submodule-mastersolution从父存储库中删除子模块。如果您想从历史记录中删除所有子模块提交,则也可以使用git filter-branch重写父代。

我曾经为35个不同的存储库做过这件事。这里有一个提示:在AWS的几个小时集群计算中花费10美元。 git filter-branch是极其受RAM限制的。您的笔记本电脑在20小时内无法完成的任务是,AWS群集计算实例可能会在午餐时间结束。这是一个非常简单,便宜的方式来进行这样的操作。

最后一个注意事项。如果您使用BSD sed,手册页中\t替换将会失败。 Jeff King的perlversion将解决该问题:

git filter-branch --index-filter ' 
    git ls-files -s | 
    perl -pe "s{\t\"?}{$&newsubdir/}" | 
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && 
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE 
' HEAD 
相关问题