主存储库的不同分支如何使用子模块的不同分支?

假设我有一个y带有某些子模块的主存储库,例如sub/x

还假设对于主模块和子模块存储库,master都是活动分支,并且.gitmodules主存储库文件指定branch = master

现在,假设master主模块(y除了其分支外,还有一个分支yA,同样,子模块repo(除了 master分支外,x还有一个分支xA

我希望回购yA分支y“查看” /使用回购xA分支x

这将意味着之间的切换masteryA在主支路回购将导致之间的对应开关masterxA分支在子模块。

git对此有任何支持吗?


我尝试了以下方法:

  1. 切换到yA主仓库上分支;
  2. 切换到xA子模块仓库上分支;
  3. 代替masterxA作为在主回购的分支参数的值.gitmodules的文件;
  4. 在主存储库中,提交由(2)和(3)引起的所有更改。

这没有按我希望的那样工作:如果我切换到master主存储库上的分支,则这对子模块存储库的活动分支设置没有影响(因此,该master分支没有干净的状态)。

星期二

git对[我想要的]有任何支持吗?

我认为有点。您将需要确保.git/modules(在超级项目中)获取设置。

TL; DR

.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--mergecheckout

现在,进入三种模式。我将再次引用该文档,随后进行一些小的格式更改和评论:

  • checkout
    超级项目中记录的提交将在独立的HEAD的子模块中检出。

  • rebase
    子模块的当前分支将重新基于超级项目中记录的提交。

  • merge
    超级项目中记录的提交将合并到子模块中的当前分支中。

因此,在默认模式下,任何分支名称都不会在任何地方输入图片。实际上,只有rebaseandmerge模式使用分支名称。所以现在我们要问一个问题:哪个分支名称?

该文档说明得很清楚:子模块中的当前分支这不是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使用的远程分支默认为remote HEAD,但是可以通过将submodule.<name>.branch选项设置.gitmodules.git/config.git/config优先)来覆盖分支名称

这适用于任何支持的更新程序(--checkout--rebase,等)。唯一的变化是目标SHA-1的来源。例如,submodule update --remote --merge将上submodule update --merge游子模块更改合并到子模块中,而将超级项目gitlink更改合并到子模块中。

那么,Alllllll-对!

认真地讲,这段文字确实很难阅读,但是它所表达的是,不仅git submodule update --remote将使用超级项目中的原始SHA-1哈希ID。相反,它将使用从其他位置获取的原始SHA-1哈希ID。确切地,其他地方在哪里?

为了确保当前跟踪分支状态,请update --remote在计算SHA-1之前获取子模块的远程存储库。如果您不想提取,则应使用submodule update --remote --no-fetch

因此:当您--remotegit submodule update命令一起使用,超级项目将:

  • 第1步(cd $path; git fetch),除非您添加--no-fetch
  • 第2步:(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记录在分支名yAbranch = xA的话,在你运行的时间git submodule update --remote(有或无--no-fetch),上层项目的Git应该做git rev-parseorigin/xA,假设子模块x具有origin作为其远程这里。这将成为超级项目运行y传递给子模块的原始哈希ID的来源xy(cd x; git checkout $hash)

当您切换到其他提交时,请注意,此处分支名称无关。重要的是提交哈希ID以及该.gitmodules提交的一部分文件-在超级项目中,超级项目中的.gitmodules文件可以具有其他branch =设置。您的git submodule update --remote命令将找到设置,并git rev-parse在超级项目告诉子模块要检出内容时让子模块Git进行其他操作以使哈希ID传递给子模块Git。

这都是非常复杂的,有很多活动部件。这些零件都必须在正确的时间排好队。超级项目最终实际上实际上只是使用原始哈希ID。仅使用正确的原始哈希ID会减少头痛的事情。一旦提交,便无法更改,通常这是正确的选择,因此您只需在提交之前确保它们正确即可。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

不同分支中的 git 子模块

Git合并策略与子模块的不同分支

Git 和 Github 显示存储库中的不同分支

如何将当前本地分支与远程存储库中不同分支的特定单个提交合并?

是否可以与子模块同步签出主存储库的分支?

如何防止以位桶组织的工作方式在同一存储库中同时建立不同分支的构建?

我应该如何在不同分支中处理不同版本的JS库?

如何在tf.map_fn的不同分支中使用不同的卷积层?

如何比较来自两个不同分支的文件?

使用每个不同分支的工作区进行Git

Git跟踪推拉的不同分支?

如何将相同的存储空间应用于git中的不同分支?

我想在我本地存储库中的git中的不同分支上工作,这些分支与原始设置为上游的分支不同

需要了解如何使用 Git Bash 将代码推送到 Bitbucket 中的不同分支

从不同分支选择提交到主分支

如何从不同的分支带来子模块?

2个本地文件夹,每个文件夹包含同一存储库的不同分支

如何从不打算受到影响的受影响分支的不同分支恢复提交?

Git:如何区分不同分支中的两个不同文件?

在不同分支中比较相同文件的正确方法

为不同分支机构部署GitLab页面

Jenkinsfile中不同分支的单独触发器

合并来自不同分支/目录的特定文件

如何使用 GIT 将我的代码从本地机器推送到除 master 之外的不同分支中的 Azure devops?

如何在不同分支上重新建立最后的x个提交?

如何在 Git 的不同分支上拆分 node_modules

Travis CI可以在同一仓库的不同分支中使用加密文件吗?

在不同分支中删除的目录即使在 git 的 master 分支中也不显示

Git将不同分支中的旧提交推送到新分支