指定git子模块的分支? [英] Specify branch for a git submodule?

查看:168
本文介绍了指定git子模块的分支?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已将git子模块添加到我的git存储库中,并且工作正常.

I have added a git submodule to my git repository and it works fine.

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

In my "parent" repository I have created a feature branch: myfeature that requires some changes to the sub module. But I don't want to affect other teams using the same sub module. Therefore I have created a corresponding feature branch on the submodule repository submodule-feature with some changes. I have then added/committet the change from the submodule directory followed by the same in the root of the parent repository.

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

But when I switch back to master on my "parent" repository the submodule is still on the submodule-feature feature branch. That is not what I expect. Because now when I run my tests on master they fail because I have introduced some breaking changes in the submodule on the submodule-feature branch.

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

Is it not possible to lock the branch of a submodule to the parent repository branch?

基于: 如何指定分支/标记添加Git子模块时?

好像我可以在.gitmodules

[submodule "mysubmodule"]
    path = mysubmodule
    url = https://bla.git
    branch = submodule-feature

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

And adding the following additional git behavior in jenkins:

和:

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

it clones/checkout the submodule-feature branch when running a build on the parent myfeature branch.

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

But that will of course require some manual steps when working locally. But from CI side its very easy to accomplish.

推荐答案

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

The short answer is just mostly "no". While Jenkins has a checkbox, it may not be a good idea to use it here—whether it is or not, depends on who controls the name-to-ID-mapping. Other CI systems may or may not have similar checkboxes. To see what I'm getting at here, read on.

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

The philosophy of submodules is that the superproject is in control of its submodules. This part, I think, is neither surprising nor objectionable to anyone. But the key lies in the way the superproject controls each submodule. This part does surprise people, and the reason is fairly simple. It's a basic misunderstanding of Git repositories in general.

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

People think that what matters in Git repositories are branches, or more precisely, branch names like master and develop. That's simply not true. These branches, for the most part, are virtually irrelevant here. For humans, these branch names serve an enormous, overriding purpose. For Git, they serve a mostly-trivial point that's equally well covered by any other name, such as a tag name, or a remote-tracking name, or refs/stash, or HEAD@{17}.1

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

In Git, the commit, not the branch name (nor tag name, nor any other name), is the central, essential thing. Commits are Git's raison d'être. Without commits, Git has no function. With commits, Git is useful. Commits are actually identified by their hash IDs, whose true names are those big ugly strings like b5101f929789889c2e536d915698f58d5c5c6b7a. Silly things like readable names, like master or develop, are for the weak, the biologicals ... the humans.

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

Of course, we, being weak humans, like our names. So we use them in our repositories. But when we have a repository that, like a superproject, is controlling another repository, such as a submodule—well, in this case, there are no humans involved. So Git uses the commit ID to control which commit hash ID is extracted in each submodule.

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

So this is where the surprise comes in—except, once you understand where Git is coming from, it's not surprising at all. When you let the superproject choose the submodule commit, the superproject chooses the submodule commit by hash ID. Any branch names are irrelevant. The hash ID is precise and is always correct. Branch names are sloppy—they move, on purpose, from commit to commit, over time. One commit hash ID can have zero or more branch names that either point directly to it, or can reach it through the commit graph.2

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

Each and every commit you make in the superproject records the exact submodule hash ID that the submodule is expected to have checked out. Hence, when you git checkout some commit in the superproject, you should generally immediately have each submodule do its own separate git checkout by the hash ID specified in the superproject.3

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

Remember that each submodule is a Git repository of its own, so it has its own HEAD, index and work-tree. The index in the submodule records the files that are checked out into the work-tree of the submodule, and the HEAD in each submodule is in detached HEAD mode, recording the hash ID of the currently-checked-out commit. It's the superproject's Git that chooses this hash ID—by storing it in a commit in the superproject—and it's the submodule's Git's responsibility to have this particular commit checked out. Nowhere in this process is there any mention of a branch name. Branch names are irrelevant!

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

1The in-Git function of names, besides of course providing a crutch for weak humans, is to protect objects from being garbage collected. An object is vulnerable to collection if it is not reachable from some name. Since most commits are mostly chained together, one name tends to protect most of the commits in a repository. See also footnote 2.

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

2For more about reachability, see Think Like (a) Git.

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

3This doesn't actually happen automatically by default. You have to use git checkout --recurse-submodules or set submodule.recurse in your configuration. Depending on what you're doing—especially, if you're trying to update the submodules—having it happen automatically is either convenient, or extremely annoying.

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

As you noted, the .gitmodules file can record a branch name. You can also copy this into .git/config (the .git/config setting overrides the .gitmodules setting, if both are set.) But typically, the submodule isn't on a branch at all; it's put into detached HEAD mode, as described above. So what good is this branch name?

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

The first, but somewhat unsatisfactory, answer is: It's no good at all. Most operations just don't use it.

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

The second, more satisfactory answer is: A few special-purpose operations do use it. Specifically, if you are in the process of updating the superproject, and want to make a new superproject commit that records a new submodule hash ID, you need some way to pick out the new submodule commit hash ID. There are multiple ways to go about this, and the name is designed for use in one of those ways.

例如,假设该子模块是您不控制的公共存储库(也许在GitHub上).您只需使用它.也许每年两次,或者一天可能有50000次,有人会更新GitHub存储库.他们将新提交提交到masterdevelop或其他内容上,会破坏您使用的一堆东西,但这不是问题,因为您的超级项目不会 say 让我最新的masterdevelop提交",您的超级项目会说让我提交a123456...",并且a123456...永远都是相同的提交,直到宇宙热死为止,或者我们将停止使用Git,以先到者为准.但是,在破坏了您自己的一堆软件的同时,他们引入了您必须具备的一项很酷的新功能.

Suppose, for instance, that the submodule is a public repository (perhaps on GitHub) that you don't control. You just use it. Perhaps twice a year, or perhaps 50000 times a day, someone updates the GitHub repository. The new commit(s) they put on their master or their develop or whatever, break(s) a bunch of stuff you use, but that's not a problem, because your superproject doesn't say "get me their latest master or develop commit", your superproject says "get me commit a123456...", and a123456... is always the same commit, forever, until the heat death of the universe, or we stop using Git, whichever occurs first. But, while breaking a bunch of your own sh— err, software, they've introduced a cool new feature that you must have.

这时您想要做的是拥有Git,它也控制着您的子模块,告诉您的子模块Git:让我了解他们最新的masterdevelop或我记录的任何名称.由于您 did 记录了该名称,因此可以使用以下命令指示Git指示子模块执行此操作:

What you would like to do at this point is have your Git, the one that's controlling your submodule too, tell your submodule Git: Go get me their latest master or develop or whatever name I recorded earlier. Since you did record that name, you can direct your Git to direct your submodule to do that using:

git submodule update --remote

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

(to which you can add some extra flags like --checkout or --rebase or --merge, but I'm not going to get into these details—I'm going to assume for now that you just use their latest directly). Your Git has your submodule Git run git fetch and then updates your submodule repository to their latest commit as directed by your submodule's copy of their branch name. (There are now at least three Gits involved in all this—your superproject, your submodule, and the Git repository on GitHub—so it's a little complicated. They, whoever they are, probably have one or more Git repositories they use to control the GitHub one, but at least you don't have to deal with that. Well, not yet.)

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

Now that your submodule is updated, you must fix up your own code, both to use the the new feature and to deal with all the breaking changes they made to stuff you were already using. So you do all of that, building and testing your software—all on your local machine: there's no CI involved here, not yet—and get it all working. Now you can git add your changes and git add the name of the submodule. Your superproject's index and work-tree now all match up and you are ready to make a new commit in your superproject.

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

Note that git add submodule-path merely told your Git to record, in your index, the hash ID of the commit that is currently checked-out in the your submodule Git repository. Once again, the branch name, if any, is irrelevant. It doesn't matter if your submodule repository is on branch master or develop, or has a detached HEAD; all that matters is the raw commit hash ID.

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

You now run git commit to make a new commit. The hash ID from your index, which controls which commit is going to be considered the "right" commit for the submodule, is the commit hash ID you recorded by running git add submodule-path. In this case, that commit ID got selected by the fact that you ran git submodule update --remote earlier. But the only thing that matters is the hash ID in your index, which goes into the new commit.

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

Now you can git push this commit, that you have made in your superproject Git repository, to some other system, such as your CI system. It can git checkout this commit, and this commit records the right submodule hash ID.

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

This is, obviously, a lot harder may be harder, depending on whether your CI system offers it as a feature.

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

Now that you know how this is all constructed, though, you have the tools you need. You must have your CI system update (or obtain) its clone of the superproject. That superproject contains, in its .gitmodules file, the URL and path for any submodules that the CI system must clone as well. It may or may not contain some branch name(s) for those submodules.

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

The CI system must now direct some Git—the superproject Git or the submodule Git—to have the submodule Git git checkout some commit other than the one already recorded as the correct commit, so that the superproject is no longer using the commit that the CI system checked out. In other words, you're no longer building what you submitted to the CI system. You are having the CI system build a new Frankenstein's-monster out of body parts: the main body from your commit, but a limb taken from some other commit that you didn't specify directly: instead, you're allowing someone else to specify which commit goes there. You gave your CI system a name and told it to ask them, whoever they are, what hash ID that name goes to.

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

Your CI system can now attempt to build and use this Frankenstein's-monster. If it all works well, your CI system will need to make a new commit, that's a lot like your commit except that it records the hash ID it got from them—whoever they are, again—for the submodule in question. Your CI system probably now also needs permission to push this commit somewhere, unless your CI system is also your main repository source-of-truth.

这篇关于指定git子模块的分支?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆