git - git子模块分支克隆
问题描述
我想做一个项目的分支,包括所有子模块中的相同分支然后在提交并推送所有子存储库和主存储库之后,我希望能够克隆新的分支以供永远使用
在我提交并且一切看起来都很好之后 - 我尝试克隆。
对于某些原因,子模型不指向新分支迫使我在子模块中进行检查/结帐
这是正常行为吗?我做错了什么/可以做得更好吗?有没有办法“克隆”所有切换分支的子模块?
谢谢你。大卫。
解决方案
TL;博士
这个是正常的。您需要编写或找到一个小包装器来处理它(或钩子:请参阅 philb 的评论)。请继续阅读详细说明。
子模块使用提交,而不是分支
这有点夸大其词,但这里主要的是它只是轻微的。如果您从这个想法开始,那么其余的一切都是有意义的。
记住什么是子模块:
首先,它是一个 Git 存储库,因此它由提交组成。它具有帮助 Git找到这些提交的分支和标签名称,但它实际上都是关于提交的。
其次——这是使它成为子模块的部分,而不仅仅是一个普通的存储库——它由其他一些 Git 存储库控制,Git 称之为这个子模块的超级项目。
理解关于子模块的一切的关键是超级项目列出了一个原始的提交哈希。超级项目 Git 将运行:
git -C path/to/submodule checkout $hash
或等效地:
git -C path/to/submodule switch --detach $hash
每当您负责超级项目时,请检查超级项目中的一些提交。此命令的$hash
值由超级项目 Git 存储库中的索引确定,索引哈希值最初是来自当前提交的值。因此,控制超级项目对子模块施加的哈希 ID 的是当前提交。
现在,这也太强了:超级项目并不总是进入子模块并运行 detached-HEAD 开关/结帐命令。它在某些特定的时间这样做。正是当它进入子模块并这样做时,我们才能了解所有血腥的细节。但这是子模块的工作方式。git submodule add -b
例如,使用选项声明子模块的分支不会改变这种行为。
显然,您希望看到的是:
git -C path/to/submodule checkout $branch
或者:
git -C path/to/submodule switch $branch
where$branch
设置为来自某个地方的分支名称。没有确切发生这种情况的内置案例,但有几种方法可以实现。
那么你什么时候在子模块中获得分支名称行为?
实际上git checkout
在每个子模块内部运行的是一个git submodule update
命令。(请参阅下面的侧边栏。)如果您查阅文档,您会看到git submodule update
有大量的选项。没有选项组合可以git submodule update
运行您想要的命令。
如果您为该结帐设置了递归选项, Git 将git checkout
在超级项目中执行自动子模块更新(再次参见侧边栏) 。也就是说,会这样做,如果您已在配置中设置为,则将这样做。显式将禁止 Git 的自动更新。git checkout --recurse-submodules
git checkout
submodule.recurse
true
git checkout --no-recurse-submodules
(请注意,除非您使用 ,否则它git clone
本身会以运行内部git checkout
命令结束。结帐将根据传递给 的标志或您设置的配置git clone --no-checkout
递归或不递归。)--recurse-submodules
git clone
如果您没有git checkout
进行自动更新,您通常会现在手动运行自己的 git submodule update
命令。您可以选择不运行git submodule update
,也可以选择运行它,但随后执行以下命令:
git -C path/to/submodule switch $branch
命令。当然,这一切都不是自动的。
侧边栏:git checkout
不使用git submodule update
用于更新子模块的面向用户的git submodule update
命令是. 但git checkout
它本身并没有真正运行git submodule update
:相反,它已经将 . 的行为硬编码到其中git submodule update --checkout
。这是,至少目前, in entry.c
,它注意到 gitlink 哈希 ID 已更改并调用submodule_move_head
insubmodule.c
,它当前使用 的调用git read-tree
,并传递给它一个原始哈希 ID。所以它不能使用所需的命令。
使用git submodule update
您可以选择子模块更新模式:
“更新”可以通过多种方式完成,具体取决于命令行选项和
submodule.<name>.update
配置变量的值。命令行选项优先于配置变量。如果两者都没有给出,checkout
则执行 a。...
checkout
超级项目中记录的提交将被签出...
这是默认设置,也是您所看到的。
rebase
子模块的当前分支将重新基于超级项目中记录的提交。
这更接近您想要的,但根本不是您想要的,而且还有一个引导问题:子模块的当前分支到底是什么?
merge
超级项目中记录的提交将被合并到子模块中的当前分支中。
这也不是您想要的,并且有同样的问题要解决。
以下
update
过程仅可通过submodule.<name>.update
配置变量获得:自定义命令
执行带有单个参数的任意 shell 命令(超级项目中记录的提交的 sha1)。当submodule.<name>.update
设置为!command时,感叹号后的余数为自定义命令。
这是唯一可以执行您想要的更新命令之一。您可以设置一个自定义命令来执行您想要的git checkout
或git switch
. 请注意,不会向您提供分支名称;你将不得不从某个地方把它捞出来。这太难了(我认为);继续阅读,或跳到结论部分,看看我认为正确的方法是什么。
none
子模块未更新
(为了完整起见,我将其包括在内,但显然不能满足您的要求。)
但是等等:还有一种选择!出于某种原因,这里没有描述;它留在选项部分。这是--remote
选项:
--remote
此选项仅对更新命令有效。不要使用超级项目记录的 SHA-1 来更新子模块,而是使用子模块的远程跟踪分支的状态。使用的遥控器是分支的遥控器 (branch.<name>.remote
),默认为origin
. 使用的远程分支默认为 remote ,但可以通过在or中设置选项HEAD
来覆盖分支名称 (优先)。submodule.<name>.branch
.gitmodules
.git/config
.git/config
这适用于任何受支持的更新过程(
--checkout
、--rebase
等)。唯一的变化是目标 SHA-1 的来源。例如,submodule update --remote --merge
将上游子模块更改合并到子模块中,而submodule update --merge
将超级项目 gitlink 更改合并到子模块中。为了确保当前跟踪分支状态,
update --remote
在计算 SHA-1 之前获取子模块的远程存储库。如果您不想获取,则应使用submodule update --remote --no-fetch
.
这几乎可以满足您的需求。有两个问题:
它运行
git -C path/to/submodule fetch
,然后git -C path/to/submodule rev-parse origin/$branch
,然后运行该步骤git -C path/to/submodule switch --detach $hash
的结果。(当两个和就足够了时,它使用三个命令来实现这一点有点愚蠢:开关可以在内部进行 rev-parse。但这是它编码方式的副作用。)$hash
rev-parse
fetch
switch --detach
这里的缺点是额外的
fetch
和使用origin/$branch
. 您可以使用 停止获取--no-fetch
,尽管它可能是无害的,并且有时可能是可取的。的使用origin/$branch
也可能是无害的:如果你刚刚克隆了子模块存储库,$branch
可能甚至不存在,结果总是会是一个分离的 HEAD,因为子模块总是分离的 HEAD,所以origin/$branch
应该没问题。更大的缺点是,如果不首先手动运行 a就无法指定。而且,无论如何,您仍然留在子模块中的一个分离的 HEAD 上!
--remote
git submodule update
结论
有没有办法“克隆”所有切换分支的子模块?
不,但是,如果您愿意使用 Git 以外的其他东西——例如,使用运行Git 的包装器——这很容易。对于您的情况,一个简单的包装器运行git clone
,然后运行一个调用命令的 shell 函数(您提供)git submodule update --init
将完成这项工作。使用(我认为)优于尝试使用自定义更新命令,因为您可以轻松访问超级项目和子模块部分,以便您可以从超级项目的设置中找出分支名称。git submodule foreach --recursive
git switch
git submodule foreach
如果足够好,您还可以使用git clone
其次git submodule update --checkout --remote
来获得正确的哈希 ID 。
推荐阅读
- javascript - AWS IoT Core 连接被经过身份验证的 Cognito 用户拒绝,带有附加策略 [MQTT over WSS]
- sql - 使用命令复制在 postgres 中出现变量连接问题
- android - Android Intent Share 无法正常工作
- corda - 使用 network-bootstrapper 生成节点信息需要带有 devMode=false 的证书
- php - 由于 .htaccess,php curl 出现 301 错误
- ios - Stripe STPAddCardViewController 导航栏未显示
- java - 如何从字符串中提取表情符号和字母字符
- html - 当我尝试将数据从父组件传递到子组件时,数据显示为未定义
- node.js - node js升级6到8版本报错
- alexa - Alexa Skill ki 手动输入