git submodule add -b
如何运作?
添加具有特定分支的子模块后,新的克隆存储库(在 git submodule update --init
之后)将处于特定提交,而不是分支本身(子模块上的 git status
显示"Not currently on any branch") .
我找不到关于子模块的分支或任何特定提交的 .gitmodules
或 .git/config
的任何信息,那么Git如何解决这个问题呢?
此外,是否可以指定标签而不是分支?
我正在使用1.6.5.2版 .
11 回答
注意:Git 1.8.2增加了跟踪分支的可能性 . 请参阅下面的一些答案 .
习惯这个有点令人困惑,但是子模块不在分支上 . 就像你说的那样,它们只是指向子模块存储库的特定提交的指针 .
这意味着,当其他人检出您的存储库或提取代码并执行git子模块更新时,子模块将签出到该特定提交 .
这对于不经常更改的子模块非常有用,因为项目中的每个人都可以在同一个提交中拥有子模块 .
如果要将子模块移动到特定标记:
然后,另一个想要将submodule_directory更改为该标记的开发人员执行此操作
git pull
提交其子模块目录指向的更改 .git submodule update
实际上合并了新代码 .我想在这里添加一个答案,它实际上只是其他答案的集合,但我认为它可能更完整 .
当你有这两件事时,你知道你有一个Git子模块 .
.gitmodules
有这样的条目:git submodule status
. Git子模块对象是特殊类型的Git对象,它们保存特定提交的SHA信息 .无论何时执行
git submodule update
,它都会使用提交中的内容填充子模块 . 由于.gitmodules
中的信息,它知道在哪里找到提交 .现在,所有
-b
都会在.gitmodules
文件中添加一行 . 所以按照相同的例子,它看起来像这样:编辑:上面只支持分支名称,而不是SHA或TAG .
子模块对象仍指向特定的提交 .
-b
选项购买的唯一功能是能够根据Vogella的答案为您的更新添加--remote
标志:它不是将子模块的内容填充到子模块指向的提交中,而是用主分支上的最新提交替换该提交,然后用该提交填充子模块 . 这可以通过djacobs7回答分两步完成 . 由于您现在已经更新了子模块对象所指向的提交,因此您必须将更改的子模块对象提交到Git存储库中 .
git submodule add -b
并不是一种神奇的方式来保持一切与分支一致 . 它只是在.gitmodules
文件中添加有关分支的信息,并为您提供在填充之前将子模块对象更新为指定分支的最新提交的选项 .注意 if you have an existing submodule which isn't tracking a branch yet ,然后(if you have git 1.8.2+):
('origin'是已从中克隆的子模块的名称'origin' .
该子模块内的
git remote -v
将显示它 . 通常,它是'origin')--remote
选项:请注意,使用Git 2.10+(2016年第3季度),您可以使用'
.
'作为分支名称:如果要更新分支后的所有子模块:
请注意,对于每个更新的子模块,结果将 almost always be a detached HEAD ,Dan Cameron中的Dan Cameron注释 .
(Clintm注释in the comments,如果运行
git submodule update --remote
,结果sha1与子模块当前所在的分支相同,它不会做任何事情,并使子模块仍然"on that branch"而不是处于分离头状态 . )为了确保实际检出分支(并且不会修改表示父代表的子模块的 special entry 的SHA1),他建议:
每个子模块仍将引用相同的SHA1,但是如果您确实进行了新的提交,则可以推送它们,因为它们将由您希望子模块跟踪的分支引用 .
在子模块中推送之后,不要忘记返回到父repo,添加,提交并推送新的SHA1用于那些已修改的子模块 .
注意使用
$toplevel
,in the comments推荐in the comments .$toplevel
于2010年5月在git1.7.2中引入:commit f030c96 .dtmland添加in the comments:
相同的命令,但更容易阅读:
umläute使用简化版in the comments优化dtmland的命令:
多行:
Git 1.8.2增加了跟踪分支的可能性 .
另见Git submodules
我如何使用Git子模块的一个例子 .
创建新存储库
然后将另一个存储库克隆为子模块
然后我们让子模块使用一个名为V3.1.2的标签
然后我们承诺 .
这看起来有点像这样:
也许它有帮助(即使我使用标签而不是分支)?
根据我的经验,在超级项目中切换分支或将来检出仍将导致子模块的分离HEAD,无论子模块是否被正确添加和跟踪(即@ djacobs7和@Johnny Z答案) .
而不是手动或通过脚本手动检出正确的分支git submodule foreach .
这将检查分支属性的子模块配置文件并检查set分支 .
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
Git子模块有点奇怪 - 它们总是处于“独立头”模式 - 它们不会像您期望的那样更新到分支上的最新提交 .
不过,当你考虑它时,这确实有些意义 . 假设我使用子模块栏创建存储库foo . 我推动我的更改,并告诉你检查从存储库foo提交a7402be .
然后想象有人在您进行克隆之前将更改提交到存储库栏 .
当您从存储库foo中检出提交a7402be时,您希望得到我推送的相同代码 . 那个's why submodules don't更新,直到你明确地告诉他们然后再做一个新的提交 .
我个人认为子模块是Git最容易混淆的部分 . 有很多地方可以比我更好地解释子模块 . 我推荐Scott Chacon的Pro Git .
要切换子模块的分支(假设您已将子模块作为存储库的一部分):
cd
到包含子模块的存储库的根目录打开
.gitmodules
进行编辑为每个子模块添加
path = ...
和url = ...
下面的行branch = your-branch
;保存文件.gitmodules
.然后不改变目录做
$ git submodule update --remote
...这应该为每个被修改的子模块提取指定分支上的最新提交 .
我在.gitconfig文件中有这个 . 它仍然是一个草案,但到目前为止证明是有用的 . 它帮助我总是将子模块重新附加到它们的分支 .
我们使用Quack从另一个Git存储库中提取特定模块 . 我们需要在没有提供的存储库的整个代码库的情况下提取代码 - 我们需要来自该庞大存储库的非常特定的模块/文件,并且每次运行更新时都应该更新 .
所以我们用这种方式实现了它:
Create configuration
使用上面的配置,它从第一个模块配置中指定的GitHub存储库创建一个目录,另一个是从给定的存储库中提取和创建文件 .
其他开发人员只需要运行
它从上面的配置中提取代码 .
为子模块选择分支的唯一效果是,每当您在
git submodule update
命令行中传递--remote
选项时,Git将以分离的HEAD模式(如果选择了默认的--checkout
行为)检出所选 remote 分支的最新提交 .你必须特别如果您使用子模块的浅克隆,那么在使用Git子模块的远程分支跟踪功能时要小心 . 您在子模块设置中为此目的选择的分支 IS NOT 将在
git submodule update --remote
期间克隆的分支 . 如果您还传递了--depth
参数,并且您没有指示Git关于要克隆的分支 - and actually you cannot 命令行中的 and actually you cannot !! - ,如果缺少显式的--branch
参数,它将隐含行为,如git-clone(1)
的git-clone(1)
文档中所述,因此 it will clone the primary branch only .毫不奇怪,在
git submodule update
命令执行克隆阶段之后,它最终将尝试检查您之前为子模块设置的 remote 分支的最新提交,如果这不是主要模块,则它不是您当地的浅层克隆,因此它会失败