子模块:核心概念、工作流程和提示
Nicola Paolucci
开发人员推广人员
相关资料
如何移动完整的 Git 存储库
查看解决方案
了解 Bitbucket Cloud 的 Git
核心概念
首先,我先简要解释一下子模块的核心概念,这将使它们更易于使用。
子模块由父项目中指定的确切提交进行跟踪,而不是分支、引用或任何其他符号引用。
更新子模块指定的存储库时,它们永远不会自动更新,只有在父项目本身更新时才会自动更新。前面提到的 Pro Git 章节中非常清楚地表达了:
当您在 [submodule] 子目录中进行变更并提交时,超级项目会注意到那里的 HEAD 已变更,并记录了您当前正在处理的确切提交,这样,当其他人克隆这个项目时,他们就可以准确地重新创建环境。
或者换句话说:
[...] git 子模块 [...] 是静态的。非常静态。您正在使用 git 子模块跟踪特定的提交——不是分支,不是引用,而是单个提交。如果您向子模块添加提交,父项目不会知道。如果您有一堆模块的拷贝,那么 git 子模块就无所谓了。您有一个远程存储库,您指向一个提交,在更新父项目之前,没有任何变更。
可能的工作流程
有用的提示即将奉上
子模块基础架构功能强大,允许对代码库进行有用的分离和集成。但是,有些简单的操作没有简化的程序或强大的命令行用户界面支持。
如果您在项目中使用 git 子模块,您要么已经遇到了这些子模块,要么即将遇到这些子模块。发生这种情况时,您将需要查找解决方案。一次又一次。我来为您节省研究时间:Instapaper、Evernote 或采用老式方法将这个页面加入书签 (:D:D),然后您就能安心一段时间了。
这是我为您准备的:
如何用自己的拷贝交换 git 子模块
这是一个非常常见的工作流程:您开始使用别人的项目作为子模块,但过了一会儿您发现需要对其进行自定义并自己进行调整,所以您需要拷贝项目,用自己的拷贝替换子模块。那是怎么做的?
子模块存储在 .gitmodules
中:
$ cat .gitmodules [submodule "ext/google-maps"] path = ext/google-maps url = git://git.naquadah.org/google-maps.git
您可以用文本编辑器编辑网址,然后运行以下命令:
$ git submodule sync
这会更新 .git/config
,其中包含这个子模块列表的副本(您也可以手动编辑 .git/config
的相关 [submodule]
部分)。
如何删除子模块?
这是一个相当常见的需求,但程序有些复杂。要删除子模块,您需要:
1. 从 .gitmodules
文件中删除相关行。
2. 从 .git/config
中删除相关部分。
3. 运行 git rm --cached path_to_submodule
(结尾处没有斜杠)。
4. 提交并删除现在未被跟踪的子模块文件。
如何将子模块重新集成到我的项目中?
或者,换句话说,如何取消 git 子模块的子模块?如果您只想把您的子模块代码放到主存储库中,只需删除子模块并将文件重新添加到主代码存储库即可:
1. 从索引中删除对子模块的引用,但保留文件:
git rm --cached submodule_path (no trailing slash)
2. 删除 .gitmodules 文件,或者如果您有多个子模块,请编辑此文件,从列表中移除子模块:
git rm .gitmodules
3. 移除 .git 元数据文件夹(确保您有此文件夹的备份):
rm -rf submodule_path/.git
4. 将 submodule
添加到主存储库索引中:
git add submodule_path git commit -m "remove submodule"
注意:上面概述的程序会破坏子模块的历史记录,如果您想保留子模块的一致历史记录,则必须进行花哨的“合并”。欲了解更多详情,请参阅这份非常完整的 Stack Overflow 引用。
如何忽略子模块的变更
有时,您的 submodules
可能会自己变为 dirty
。例如,如果您使用 Git submodules
来跟踪您的 vim 插件,它们可能会生成或修改 helptags
等本地文件。遗憾的是,git status 会开始让您对这些变更感到烦恼,虽然您对它们根本不感兴趣,也无意提交它们。
解决方案非常简单,打开存储库根目录下的 .gitmodules
文件,对于要忽略的每个子模块,添加 ignore = dirty
,如下例所示:
[submodule ".vim/bundle/msanders-snipmate"] path = .vim/bundle/msanders-snipmate url = git://github.com/msanders/snipmate.vim.git ignore = dirty
感谢 Nils 的精彩解释。
危险地带!与远程存储库互动的陷阱
正如 kernel.org 上的 Git 子模块教程提醒的那样,在与远程存储库交互时,需要注意一些重要事项。
第一种是始终发布子模块变更,然后再将变更发布到引用它的超级项目。这很关键,因为它可能会阻碍其他人克隆存储库。
第二个是永远记住在运行 git submodule update
之前提交所有变更,就好像有变更会被覆盖一样!
总结
有了这些笔记,您应该能够处理使用子模块时出现的许多常见的重复工作流程。在以后的文章中,我将介绍 git submodule
的替代方案。
关注我 @durdn 和很棒的 @Bitbucket 团队,了解更多 DVCS 优势。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。