我们有一个存储库,其中几个目录已在两年前被提取为子模块。
由于 git 子模块引起了太多麻烦,因此决定将提取恢复为子模块并将目录带回父存储库。
现在的问题是,最好的方法是什么——同时保留所有历史。
我正在考虑将子模块添加为远程,然后进行cherry-pick
所有更改。但为此我需要告诉 git 它不应该处理相对于当前目录的提交路径,而不是父 repo 的根目录。
有没有办法用cherry-pick
或任何其他聪明的方式做到这一点?
非常感谢!
我们有一个存储库,其中几个目录已在两年前被提取为子模块。
由于 git 子模块引起了太多麻烦,因此决定将提取恢复为子模块并将目录带回父存储库。
现在的问题是,最好的方法是什么——同时保留所有历史。
我正在考虑将子模块添加为远程,然后进行cherry-pick
所有更改。但为此我需要告诉 git 它不应该处理相对于当前目录的提交路径,而不是父 repo 的根目录。
有没有办法用cherry-pick
或任何其他聪明的方式做到这一点?
非常感谢!
您可以使用手册页中的示例或此答案git filter-branch
中稍作修改的版本来执行此操作。这是 git 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
首先,将每个子模块添加为父 repo 中的远程,然后将每个子模块的master
分支检出为本地跟踪分支(例如submoduleA-master
,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 版本的解决方案从父存储库中删除子模块,然后. 如果您也想从历史记录中删除所有子模块提交,您也可以使用.git merge submodule-master
git filter-branch
我曾经为 35 个不同的存储库做过这个。这里有一个提示:在 AWS 中花费 10 美元进行几个小时的集群计算。git filter-branch
非常受 RAM 限制。您的笔记本电脑无法在 20 小时内完成的事情,AWS 集群计算实例可以在午餐时间完成。这是进行此类操作的一种非常简单、便宜的方式。
最后一点。如果您使用 BSD ,那么手册页中的替换sed
很有可能会失败。\t
Jeff King 的perl
版本将解决这个问题:
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