对Git子模块进行非子模块化,将所有代码带回核心存储库的最佳实践是什么?


当前回答

下面是@gyim的回答的一个稍微改进的版本(IMHO)。他在主工作副本中做了很多危险的改变,我认为在独立的克隆上操作,然后在最后将它们合并在一起要容易得多。

在一个单独的目录中(使错误更容易清理并再次尝试)检出顶部回购和子回购。

git clone ../main_repo main.tmp
git clone ../main_repo/sub_repo sub.tmp

首先编辑subrepo以将所有文件移动到所需的子目录中

cd sub.tmp
mkdir sub_repo_path
git mv `ls | grep -v sub_repo_path` sub_repo_path/
git commit -m "Moved entire subrepo into sub_repo_path"

注意头部

SUBREPO_HEAD=`git reflog | awk '{ print $1; exit; }'`

现在从主回购中删除子回购

cd ../main.tmp
rmdir sub_repo_path
vi .gitmodules  # remove config for submodule
git add -A
git commit -m "Removed submodule sub_repo_path in preparation for merge"

最后,合并它们

git fetch ../sub.tmp
# remove --allow-unrelated-histories if using git older than 2.9.0
git merge --allow-unrelated-histories $SUBREPO_HEAD

并完成了!安全而且没有任何魔法。

其他回答

从git 1.8.5(2013年11月)开始(没有保留子模块的历史):

mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule

将:

注销和卸载(即删除子模块的内容)(deinit,因此mv先), 清理你的。gitmodules (rm), 并删除父repo (rm)索引中表示子模块SHA1的特殊条目。

一旦子模块的删除完成(deinit和git rm),您可以重命名文件夹为原来的名称,并将其作为常规文件夹添加到git repo中。

注意:如果子模块是由旧Git(< 1.8)创建的,您可能需要删除子模块本身中嵌套的.git文件夹,正如Simon East所评论的那样


如果你需要保留子模块的历史,请参阅jsears的答案,它使用git filter-branch。

这里有很多答案,但它们似乎都过于复杂,可能不能达到你想要的效果。我相信大多数人都想保留他们的历史。

在这个例子中,主repo将是git@site.com:main/main.git,子模块repo将是git@site.com:main/child.git。这假设子模块位于父repo的根目录中。根据需要调整说明书。

首先克隆父repo并删除旧的子模块。

git clone git@site.com:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"

现在我们将把子回购添加到主回购的上游。

git remote add upstream git@site.com:main/child.git
git fetch upstream
git checkout -b merge-prep upstream/master

下一步假设您希望将merge-prep分支上的文件移动到与上面的子模块相同的位置,尽管您可以通过更改文件路径轻松更改位置。

mkdir child

将除.git文件夹外的所有文件夹和文件移动到子文件夹中。

git add --all
git commit -m "merge prep"

现在您可以简单地将文件合并回主分支。

git checkout master
git merge merge-prep # --allow-unrelated-histories merge-prep flag may be required 

在运行git push之前,环顾四周,确保一切看起来都很好

你现在必须记住的一件事是,git日志默认情况下不会跟踪移动的文件,但是通过运行git log——follow filename,你可以看到你文件的完整历史。

我找到的最佳答案是:

http://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

这篇文章很好地解释了这个过程。

基于VonC的回答,我创建了一个简单的bash脚本。最后的add必须使用通配符,否则它将撤销子模块本身先前的rm。重要的是要添加子模块目录的内容,而不是在add命令中命名目录本身。

在一个名为git- integration -submodule的文件中:

#!/usr/bin/env bash
mv "$1" "${1}_"
git submodule deinit "$1"
git rm "$1"
mv "${1}_" "$1"
git add "$1/**"

git rm [-r] --cached submodule_path

返回

fatal: pathspec 'emr/normalizers/' did not match any files

背景:我在子模块文件夹中执行了rm -r .git*,然后才意识到它们需要在我刚刚添加它们的主项目中去子模块化。我得到了上面的错误去子模化一些,但不是所有的。不管怎样,我通过运行(当然,在rm -r .git*之后)来修复它们。

mv submodule_path submodule_path.temp
git add -A .
git commit -m "De-submodulization phase 1/2"
mv submodule_path.temp submodule_path
git add -A .
git commit -m "De-submodulization phase 2/2"

注意,这并不能保存历史。