在超级项目中提交和推送更改时,如何强制在git子模块上使用特定分支?

时间:2019-11-06 01:03:07

标签: git git-submodules

我想这样做,所以当在超级项目中推送发布分支时,我可以在子模块中强制发布分支

1 个答案:

答案 0 :(得分:2)

TL; DR

子模块分支名称仅在您在该子模块中进行实际工作时以及何时才是重要的,即使如此,也只有这样,您才可以轻松地从该子模块中git push。否则,只有子模块内部的实际原始哈希ID才重要。 Git通常会将子模块设置为带有“分离的HEAD”。虽然可以在较新版本的Git中存储子名称以与子模块一起使用,但在超级项目中工作时,Git确实从未使用该名称。它只使用提交哈希ID。

可以使用基于该子模块上游名称的名称,使超级项目git checkout在子模块中提交(分离的HEAD)。当在子模块上不工作而其他人却可以工作时,这有时很有用:您可能想获取他们的最新提交,查看它是否适用于您的项目,如果可以,请切换您的项目项目以使用其最新提交。在这里,分支名称有点有用,因为git submodule update --remote可以使用它来让您的子模块克隆调用 Git,查看其Git的分支名称,并为您获取哈希ID。但这实际上是针对开发过程,而不是发布过程。

简短的答案通常是“您不能直接这样做”,但大多数情况下是“无关紧要”。

事实是,对于一个超级项目,即使子模块中分支的存在也无关紧要,更不用说那些分支的名称以及它们对应的哈希ID了。 超级项目中的每个提交都记录要在子模块中使用的提交的原始哈希ID。

让这个例子更具体一些。假设我们有一个名为 P 的项目。该存储库-称为 RepoP -其中包含一些提交。该存储库具有一些分支名称,例如masterfeature/f,也许还有release/v1等。它还可能具有标签名称,例如v1.0,它是分支release/v1中代表版本1.0的特定版本。

这些名称(masterfeature/fv1.0等)在RepoP中名称​​一个特定的提交分支名称和 tag 名称之间的区别在于分支名称会随着时间的推移而变化:今天,master可能是提交的a123456...,而明天可能是b789abc...。标记名称永不更改:它始终代表相同的提交。

当您在RepoP中执行git checkout时,无论您使用分支名称还是标记名称,还是仅使用原始提交哈希,Git都会首先弄清楚这是哪个提交。也就是说,Git会找到目标提交的实际哈希ID。然后,Git将提交的内容(快照中的所有文件)提取到Git的索引/暂存区域中,并提取到RepoP的工作树中。

如果该提交有一些子模块,那么这些子模块也将进入索引。他们还没有进入工作树-还没有!但是Git会在需要时将它们创建到一个空目录(只需一会儿)。

假设您使用的名称在RepoP中选择了提交a123456...。进一步说,提交a123456...调用两个子模块,分别提取到path/to/s1s2中(没有前导目录路径,只有./s2)。在提交a123456中,您将找到Git称为 gitlinks 的两个实体:它们包含path/to/s1和原始哈希ID,以及s2和第二个原始哈希ID 。 Git还将所有gitlink都读入索引,以便它们可以永久保存在您所做的 next 提交中。

假设path/to/s1的gitlink具有哈希ID 5100000...,而s2的gitlink具有hash ID 5200000...。 (这些是不太可能的,但与a123456...a6496b61...或其他任何东西一样都不太可能。事实是,如果此提交调用这两个子模块,那么无论它们是什么,都会有两个哈希ID。)

现在,提交a123456在您的工作树中,现在 Git可以继续填写子模块了。您可能需要运行:

git submodule update --init

此时,要使其手动执行所有操作,或者您可能已经使用使Git自动执行此操作的选项来完成git checkout,但是现在您要指示Git填写子模块

Git现在将进入目录path/to/s1 ,如有必要,克隆子模块存储库,然后运行:

git checkout 5100000...

在子模块的子目录path/to/s1中获取特定的提交。 (请记住,我们说过path/to/s1的gitlink条目现在在您的索引中说与此提交一起使用提交510000... 。这就是Git所做的。)

Git将进入子目录s2,根据需要克隆子模块,然后运行:

git checkout 5200000...

特定提交在子模块的子目录s2中检出。

请注意,路径和提交哈希ID来自超级项目。 Git从未在子模块中查看 any 分支名称。子模块的分支名称根本没关系。 1

Git使用存储在 superproject 中的提交哈希ID将每个子模块存储库置于分离的HEAD 状态。 您只需要将正确的哈希ID存储到超级项目中即可。嗯,也就是说,您只需要执行 并确保这些提交存在 in < / em>克隆子模块时的子模块。


1 除了,即在此子模块的原始git clone期间:Git需要 find 提交,并且要查找提交,Git需要一些名称。这是因为哈希ID看起来完全是随机的。除非您有一个像release/1.0这样的分支名,它保存着release/1.0分支的最新哈希ID,否则无法分辨出哪些是最新的提交。


那么什么时候子模块分支名称重要?

假设您要在RepoP工作树中对项目P做一些工作。

您需要做的工作包括为子模块s2修复错误或添加功能。因此,在此窗口或其他窗口中,输入s2

您现在位于子模块Git存储库中。 git status显示您具有分离的HEAD ,因为超级项目Git告诉子模块Git:签出提交5200000...作为分离的HEAD ,并且是的。

您现在可以修改代码并进行提交,但是如果这样做,它们将仅位于此分离的HEAD上。很难将它们推到其他Git上。所以现在,您可能希望进入一个分支。

较新版本的Git允许您让超级项目Git指导子模块Git按名称签出分支。 您现在必须在超级项目中发出命令才能执行此操作。 2 但是,如果您要自己在s2内部进行一些工作,您可以在git checkout内发出一个简单的s2命令,同时处理子模块:

git checkout release/1.0

例如。现在,您可以照常进行工作并提交,这将使新的提交更改存储在子模块的分支名称release/1.0中的哈希ID。然后,您可以git push对子模块的origin进行最终提交,以将其也添加到那个存储库的release/1.0

让我们说,仅是为了具体性,您在进行此新提交时就为其分配了哈希ID 5200001...。现在,具有新功能的新提交已存在于子模块中,并已推送到origin,您只需返回到超级项目并使用git add来更新索引中的索引/暂存区超级项目Git:

git add s2

您在RepoP中所做的 next 提交将说:使用此提交时,告诉Git子模块s2签出提交5200001...

使用的任何人都通过其分离的HEAD原始哈希ID来使用它。分支名称与超级项目无关。您只需要在子模块中工作时使用它,即可将新的提交推送到origin,这样,克隆该子模块的每个人也将获得提交5200001...


2 我相信较新版本的Git会在此处提供一些更高级的控件,这可能会使您的工作稍微容易一些,尤其是在有多个需要执行的子模块的情况下。但是,实际上,git submodule newsubcommand release/1.0cd s2跟工作很容易,而cd s2git checkout release/1.0跟工作很容易吗?