指定git子模块的分支?

时间:2019-03-02 20:31:29

标签: git

我已经在git存储库中添加了一个git子模块,并且工作正常。

在我的“父”存储库中,我创建了一个功能分支: myfeature ,该分支需要对子模块进行一些更改。但是我不想影响使用相同子模块的其他团队。因此,我在子模块存储库 submodule-feature 上创建了相应的功能分支,并进行了一些更改。然后,我从子模块目录添加/提交更改,然后在父存储库的根目录中添加更改。

但是,当我在“父”存储库上切换回 master 时,子模块仍位于 submodule-feature 功能分支上。那不是我所期望的。因为现在当我在 master 上运行测试时,它们失败了,因为我在 submodule-feature 分支的子模块中引入了一些重大更改。

是否不可能将子模块的分支锁定到父存储库分支?

编辑: 基于: TheIncorrigible1

好像我可以在.gitmodules

中为子模块存储库指定一个分支
[submodule "mysubmodule"]
    path = mysubmodule
    url = https://bla.git
    branch = submodule-feature

并在jenkins中添加以下其他git行为:

How can I specify a branch/tag when adding a Git submodule?

和:

enter image description here

parent myfeature 分支上运行构建时,它将克隆/签出submodule-feature分支。

但是,在本地工作时,这当然需要一些手动步骤。但是从CI的角度来看,它非常容易实现。

1 个答案:

答案 0 :(得分:0)

简短的回答是 just 大多是“否”。尽管詹金斯(Jenkins)有一个复选框,但在此处使用它可能不是一个好主意-是否使用,取决于谁控制名称到ID的映射。其他CI系统可能具有也可能没有相似的复选框。要了解我在这里的意思,请继续阅读。

子模块的原理是,超级项目由其子模块控制。我认为,这部分内容对于任何人都不会感到惊讶或反对。但是关键在于超级项目控制每个子模块的 way 。这部分确实使人们感到惊讶,原因很简单。一般来说,这是对Git存储库的基本误解。

人们认为,Git存储库中重要的是分支,或更确切地说,是分支名称,例如masterdevelop。那根本不是真的。这些分支在很大程度上实际上不相关。对于人类而言,这些分支名称具有巨大的,压倒一切的目的。对于Git,它们提供了一个几乎不重要的点,该点也可以被其他任何名称(例如标记名或远程跟踪名称或refs/stashHEAD@{17})覆盖。 1

在Git中, commit (而不是分支名称)(不是标签名称,也不是其他任何名称)是核心的基本内容。提交是Git的raison d'être。没有提交,Git将不起作用。对于提交,Git很有用。提交实际上是由其哈希ID标识的,其真实名称是诸如b5101f929789889c2e536d915698f58d5c5c6b7a之类的丑陋大字符串。诸如masterdevelop之类的可读名称之类的愚蠢事物是为弱者,生物学家...为人类服务的。

当然,我们作为弱者,很喜欢我们的名字。因此,我们在存储库中使用它们。但是,当我们拥有一个像超级项目一样的存储库来控制另一个存储库(例如子模块)时,那么,在这种情况下,没有人参与。因此,Git使用提交ID来控制在每个子模块中提取哪个提交哈希ID。

所以这就是惊喜的源头-除了一旦您了解了Git的来源,就一点也不奇怪了。 当您让超级项目选择子模块提交时,超级项目通过哈希ID选择子模块提交。任何分支名称都不相关。哈希ID准确且始终正确。分支名称草率—它们随着时间的推移故意从提交更改为移动。一个提交哈希ID可以具有零个或多个直接指向它的分支名称,或者可以通过提交图到达它。 2

您在超级项目 in 中所做的每一次提交都记录了预期子模块已经签出的确切子模块哈希ID。因此,当您在超级项目中git checkout进行某些提交时,通常应该立即让每个子模块通过超级项目中指定的哈希ID单独执行git checkout。 3

请记住,每个子模块都是其自己的Git存储库,因此它具有自己的HEAD,索引和工作树。子模块中的索引记录了检出到子模块工作树中的文件,每个子模块中的HEAD处于分离头模式,记录了文件的哈希ID。当前已检出的提交。通过将散列ID存储在超级项目中的提交中,是选择该哈希ID的是超级项目的Git,并且要检出此特定的提交是子模块的Git的责任。在此过程中,没有任何地方提到分支名称。分支名称无关!


1 名称的in-Git功能除了为弱者提供了拐杖外,还可以防止物体被垃圾收集。如果某个对象无法通过某些名称访问,则该对象很容易被收集。由于大多数提交大多是链接在一起的,因此一个名称倾向于保护存储库中的大多数提交。另请参见脚注2。

2 有关可达性的更多信息,请参见Think Like (a) Git

3 默认情况下,这实际上不会自动发生。您必须在配置中使用git checkout --recurse-submodules或设置submodule.recurse。根据您正在执行的操作,尤其是如果您要更新子模块,自动进行操作既方便又非常烦人。


那么,为什么可以首先设置分支名称?

如您所述,.gitmodules文件可以记录分支名称。您也可以将其复制到.git/config中(如果同时设置了.git/config,则.gitmodules设置将覆盖master。)但是通常,子模块根本不在分支上;如上所述,它已进入分离HEAD模式。那么这个分支名称​​ 有什么用呢?

第一个但有些不令人满意的答案是:一点都不好。大多数操作只是不使用它。

第二个更令人满意的答案是:一些特殊用途的操作确实在使用它。具体来说,如果您正在更新超级项目,并且想要进行记录 new 子模块哈希ID的新超级项目提交,则需要某种方法来挑选新的子模块提交哈希ID。解决此问题的方法有多种,而名称专门用于其中的一种。

例如,假设该子模块是您不控制的公共存储库(也许在GitHub上)。您只需使用它。也许每年两次,或者一天可能有50000次,那么有人会更新GitHub存储库。他们在developmaster或其他任何东西上提交的新提交会破坏您使用的一堆东西,但这不是问题,因为您的超级项目不会“获取最新的developa123456...提交”,您的超级项目说“获取我的提交a123456...”,而master始终是相同的提交,直到宇宙热死为止,或者我们停止使用Git,以先到者为准。但是,在破坏了您自己的一堆软件的同时,他们引入了您必须具备的一项很酷的新功能。

这时您想要做的就是拥有Git,它也控制着您的子模块,告诉您的子模块Git:请给我最新的developgit submodule update --remote 因为您 did 记录了该名称,所以您可以使用以下命令指示Git来指示子模块执行该操作:

--checkout

(您可以在其中添加一些额外的标志,例如--rebase--mergegit fetch,但我不打算讨论这些详细信息,而是假设现在您只需直接使用其最新信息即可)。您的Git会让您的子模块Git运行git add,然后根据您的子模块的分支名称副本将您的子模块存储库更新为最新提交。 (现在至少有三个参与了这三个Git —您的超级项目,您的子模块和GitHub上的Git存储库—因此有点复杂。无论他们是谁,他们可能都有一个或多个他们用来控制GitHub的Git存储库,但至少您不必处理它。嗯,还没有。)

现在,您的子模块已更新,您必须修复自己的代码,才能使用新功能并处理它们对已使用的东西所做的所有重大更改。因此,您需要做所有这些,在本地计算机上构建和测试软件,而且都不需要在这里使用CI,并且可以正常工作。 现在,您可以git add进行更改,并git add submodule-path子模块的名称。现在,您的超级项目的索引和工作树都匹配了,您可以在超级项目中进行新的提交了。

请注意,master仅告诉您的Git在索引中记录了当前在子模块Git存储库中检出的提交的哈希ID 。再次,分支名称(如果有的话)是不相关的。子模块存储库是在分支developgit commit上还是具有独立的HEAD都无关紧要。重要的是原始提交哈希ID

您现在运行git add submodule-path进行新的提交。索引中的哈希ID是您通过运行git submodule update --remote记录的提交哈希ID,该哈希ID控制哪个提交将被视为子模块的“正确”提交。 在这种情况下,由于您早先运行了git push,所以选择了该提交ID。但是唯一重要的是索引中的哈希ID,该ID进入新的提交。

现在,您可以git checkout将此提交(在超级项目Git存储库中所做的)提交到其他系统,例如CI系统。它可以.gitmodules进行此提交,并且此提交记录 right 子模块哈希ID。

如何将其与CI系统结合使用,以便CI系统选择哈希ID?

根据您的CI系统是否提供此功能,显然要难得多

现在,尽管您知道这是如何构造的,但是您拥有所需的工具。您必须具有CI系统更新(或获取)超级项目的克隆。该超级项目的git checkout文件中包含CI系统必须克隆的所有子模块的URL和路径。它可能包含也可能不包含这些子模块的某些分支名称。

CI系统现在必须引导某些Git(超级项目Git或子模块Git),以使子模块Git {{1}}进行一些提交,而不是已被记录为的提交。正确的提交,以便超级项目不再使用CI系统签出的提交。换句话说,您不再构建提交给CI系统的内容。您正在使用CI系统从身体部位构建新的科学怪人的怪兽:提交中的主体,但取自您未直接指定的其他提交中的肢体:允许其他人指定要提交的提交内容。您为CI系统指定了一个名称,并要求其询问他们(无论是谁)该名称到达的哈希ID。

您的CI系统现在可以尝试构建和使用此科学怪人的怪物。如果一切正常,则您的CI系统将需要进行 new 提交,与 your 提交非常相似,除了它记录哈希ID it 是从 them (无论它们是谁)获得的,用于所讨论的子模块。除非您的CI系统也是您的主要存储库的真实来源,否则您的CI系统现在可能还需要权限才能将该提交推送到某个地方。