假设我有一个y
带有某些子模块的主存储库,例如sub/x
。
还假设对于主模块和子模块存储库,master
都是活动分支,并且.gitmodules
主存储库的文件指定branch = master
。
现在,假设master
主模块(y
)除了其分支外,还有一个分支yA
,同样,子模块repo()除了其 master
分支外,x
还有一个分支xA
。
我希望回购的yA
分支y
“查看” /使用回购的xA
分支x
。
这将意味着之间的切换master
和yA
在主支路回购将导致之间的对应开关master
和xA
分支在子模块。
git对此有任何支持吗?
我尝试了以下方法:
yA
主仓库上的分支;xA
子模块仓库上的分支;master
用xA
作为在主回购的分支参数的值.gitmodules
的文件;这没有按我希望的那样工作:如果我切换到master
主存储库上的分支,则这对子模块存储库的活动分支设置没有影响(因此,该master
分支没有干净的状态)。
git对[我想要的]有任何支持吗?
我认为有点。您将需要确保.git/modules
(在超级项目中)未获取设置。
在.gitmodules
(在超级项目中)提交中使用不同的设置,并git submodule update --remote
根据需要使用。我尚未对此进行测试,但是请参见详细说明。
我的总体总体建议:branch
子模块的设置通常是无用且无关紧要的。只是忽略它。不过,稍后我们将介绍大部分内容,您可以查看是否可以使用它。
子模块定义为一个Git存储库,其中一些其他Git有时会进入该子模块并运行一些Git命令。另一个Git被称为超级项目。
超级项目Git的主要操作是:
(cd $path && git checkout $hash)
在此顺序中,没有任何分支名称出现。这就是为什么在branch
设置无关。
在$path
与$hash
部分来自上层项目的Git的指数,他们到了那里通过被提取从在上层项目提交。该提交记录了子模块的路径以及原始哈希ID。在此也没有分支名称出现。
当您在超级项目中运行git checkout
或运行时git switch
,为了选择一些分支名称并因此选择某个特定的提交,超级项目Git将提取提交到其(超级项目的)索引以及该超级项目的工作树的提交。这会将正确的($ path,$ hash)对放入超级项目的索引中。
不幸的是,默认情况下它不调用该$(cd $path && git checkout $hash)
部分来更新子模块。为此,您有几种选择:
git submodule update
。该命令正是这样做的(嗯,默认情况下:请参见下面的详细信息)。git checkout --recurse-submodules
(或对标记相同git switch
)。此命令git checkout
运行更新,并传播到子模块Git中,以便在该子模块运行git checkout
(或git switch
)时,如果该子模块是另一个子模块的超级项目,则该子模块将以其超级项目角色调用更新。对于所有嵌套的子模块,这将(递归)重复。(我通常不使用它,但是我不必过多地处理递归子模块。由于递归,它非常强大。)submodule.recurse
为true。这将启用--recurse-submodules
多个命令的选项,包括签出/切换功能,git fetch
以及和git pull
。(我不喜欢这个:我认为它太强大了。但是,您可以对其进行设置,然后使用该push.recurseSubmodules
设置显式禁用递归推送。)branch
设定回事?该git submodule
文档有几个很长且相当清晰的段落来描述该git submodule update
子命令。(我认为这表明子模块的整体设置存在缺陷,但是我们必须使用已有的东西,至少要等到提出更好的东西为止。)让我在这里引用一下:
update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--] [<path>...]
通过克隆丢失的子模块,在子模块中获取丢失的提交并更新子模块的工作树,来更新已注册的子模块以符合超级项目的期望。根据命令行选项和submodule.<name>.update
配置变量的值,可以用几种方式完成“更新” 。...
如您所见,有很多选择。为了保持这个答案从得到更长的时间,让我们集中精力只是其中之三:--checkout
,--rebase
,和--merge
。还有两个不是选项,但您可以使用变量设置,在这里我们将忽略它。这些选项,,和设置更新将使用的操作类型,与不带前导双连字符的选项名称相同。submodule.name.update
--checkout
--rebase
--merge
该checkout
模式是默认默认模式。也就是说,如果您未设置显式设置,并且未指定或,则会得到。这就是每个人都使用的-主要是!因此,这就是该答案顶部总体建议中的大部分内容。submodule.name.update
--rebase
--merge
checkout
现在,进入三种模式。我将再次引用该文档,随后进行一些小的格式更改和评论:
checkout
超级项目中记录的提交将在独立的HEAD的子模块中检出。
rebase
子模块的当前分支将重新基于超级项目中记录的提交。
merge
超级项目中记录的提交将合并到子模块中的当前分支中。
因此,在默认模式下,任何分支名称都不会在任何地方输入图片。实际上,只有rebase
andmerge
模式使用分支名称。所以现在我们要问一个问题:哪个分支名称?
该文档说明得很清楚:子模块中的当前分支。这不是branch =
设置的子模块; 它是当前分支中的子模块。
但是子模块中当前有哪个分支?您可以找出,如果您喜欢:
(cd $path && git rev-parse --abbrev-ref HEAD)
会告诉您,对于您经过的每条路径,当前的分支是什么。HEAD
如果子模块正在使用HEAD分离模式,则将进行打印,如果已运行git submodule update --checkout
,则将进行打印,或者git submodule update
使用checkout
模式的任何模块都将进行打印。
如果要预测当前分支,或者子模块是否位于分离的HEAD上,并因此位于任何分支上,那么您将如何预测?好吧,你跑了git submodule update
吗?git submodule update --init
除非您进行了递归模式检出,否则您必须先进行一次操作,在这种情况下,Git会git submodule update --init --checkout
为您做一个。因此,您的子模块很可能处于HEAD分离模式,因此没有当前分支。
换句话说,我们仍在海上。我们如何首先将子模块Git放在分支上?
有一种简单明了的方法:我们可以在自己(cd $path; git checkout $branch)
提供$path
和$branch
自己提供的地方做自己的事。这样,无论提交什么内容,子模块都在我们想要的分支上。但是由于我们提供了$branch
,我们不需要设置。我们只是做:
(cd path/to/submodule; git checkout feature/foo)
直。所以也不是。
如果我们向下滚动到文档中的OPTIONS部分,然后再向下滚动到该--remote
选项,我们最终会找到一个实际使用设置的地方:
--remote
此选项仅对update命令有效。而不是使用超级项目的记录的SHA-1来更新子模块,而要使用子模块的远程跟踪分支的状态。所使用的遥控器是分支机构的遥控器(branch.<name>.remote
),默认为origin
。使用的远程分支默认为remoteHEAD
,但是可以通过将submodule.<name>.branch
选项设置为.gitmodules
或.git/config
(.git/config
优先)来覆盖分支名称。这适用于任何支持的更新程序(
--checkout
,--rebase
,等)。唯一的变化是目标SHA-1的来源。例如,submodule update --remote --merge
将上submodule update --merge
游子模块更改合并到子模块中,而将超级项目gitlink更改合并到子模块中。
认真地讲,这段文字确实很难阅读,但是它所表达的是,不仅git submodule update --remote
将使用超级项目中的原始SHA-1哈希ID。相反,它将使用从其他位置获取的原始SHA-1哈希ID。确切地,其他地方在哪里?
为了确保当前跟踪分支状态,请
update --remote
在计算SHA-1之前获取子模块的远程存储库。如果您不想提取,则应使用submodule update --remote --no-fetch
。
因此:当您--remote
与git submodule update
命令一起使用时,超级项目将:
(cd $path; git fetch)
,除非您添加--no-fetch
(cd $path; git rev-parse $(complicated))
获取哈希ID。该$(complicated)
部分很复杂,但是它从branch =
设置中获取分支名称,例如branch = master
,从.gitmodules
或中.git/config
。它将变成远程跟踪名称,例如origin/master
,步骤1将刚刚更新。另请参见VonC的回答来添加一个Git子模块的时候我怎么能指定一个分支/标签?。
特殊名称.
意味着在超级项目中使用分支名称,但是:
我希望回购的
yA
分支y
“查看” /使用回购的xA
分支x
。
除非拼写完全匹配,否则您将无法获得成功.
。并且,如果子模块的分支名称已复制到超级项目的.git/config
,则它将保持设置为设置的值,否则,超级项目Git将从文件中读取branch =
设置.gitmodules
。
如果.gitmodules
文件中的主存储库提交致力于$SHA_YA
记录在分支名yA
说branch = xA
的话,在你运行的时间git submodule update --remote
(有或无--no-fetch
),上层项目的Git应该做git rev-parse
的origin/xA
,假设子模块x
具有origin
作为其远程这里。这将成为超级项目运行时y
传递给子模块的原始哈希ID的来源。x
y
(cd x; git checkout $hash)
当您切换到其他提交时,请注意,此处的分支名称无关。重要的是提交哈希ID以及该.gitmodules
提交的一部分文件-在超级项目中,超级项目中的.gitmodules
文件可以具有其他branch =
设置。您的git submodule update --remote
命令将找到该设置,并git rev-parse
在超级项目告诉子模块要检出内容时让子模块Git进行其他操作以使哈希ID传递给子模块Git。
这都是非常复杂的,有很多活动部件。这些零件都必须在正确的时间排好队。超级项目最终实际上实际上只是使用原始哈希ID。仅使用正确的原始哈希ID会减少头痛的事情。一旦提交,便无法更改,通常这是正确的选择,因此您只需在提交之前确保它们正确即可。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句