子模块和“git pull --rebase”

Jam*_*ead 5 git macos git-pull git-submodules

我们最近切换到 git 并尝试使用子模块来包含我们的公共库。

无论我们做什么,我们都无法让“git pull --rebase”在超级或子模块中工作。

我们得到:

james:libraries james$ git pull --rebase
Cannot pull with rebase: You have unstaged changes.
Please commit or stash them.
Run Code Online (Sandbox Code Playgroud)

即使我们根本没有任何本地更改并且有一个干净的目录,也会发生这种情况。有什么想法我们可能做错了什么吗?

谢谢!詹姆士

Von*_*onC 6

我们无法让“git pull --rebase”在超级或子模块中工作

为了确保涉及子模块,请使用 Git 2.14(2017 年第 3 季度,OP 提出问题 6 年后)或更高版本以及“ git pull --rebase --recurse-submodules”,它学会了将子模块中的分支重新设置为更新的基础。

请参阅Stefan Beller的提交 e8906a9(2017 年 6 月 27 日)、提交 a6d7eb2提交 8c69832提交 886dc15(2017 年 6 月 23 日)(由Junio C Hamano 合并 -- --提交 c9c63ee中,2017 年 7 月 13 日)stefanbeller
gitster

pull:可选地重新设置子模块的基础(仅远程子模块更改)

签字人: Brandon Williams
签字人: Stefan Beller

教导pull在提供“--recurse-submodules”时选择性地更新子模块。

这将教导在特定情况下给出“ ”和“ ”标志时pull运行“ ” 。submodule update --rebase--recurse-submodules--rebase

在变基工作流程中:

  1. 双方都改变子模块

让我们假设子模块中有以下历史记录:

H---I---J---K---L local branch
     \
      M---N---O---P remote branch
Run Code Online (Sandbox Code Playgroud)

以及超级项目中的以下内容(在括号中记录子模块):

A(H)---B(I)---F(K)---G(L)  local branch
        \
         C(N)---D(N)---E(P) remote branch
Run Code Online (Sandbox Code Playgroud)

在理想的情况下,这将重新设置子模块的基础并重写超级项目指向的子模块指针,使得超级项目看起来像

A(H)---B(I)              F(K')---G(L')  rebased branch
        \               /
         C(N)---D(N)---E(P) remote branch
Run Code Online (Sandbox Code Playgroud)

子模块为:

      J---K---L (old dangeling tip)
     /
H---I               J'---K'---L' rebased branch
     \             /
      M---N---O---P remote branch
Run Code Online (Sandbox Code Playgroud)

如果子模块中出现冲突,超级项目变基将在发生子模块冲突的提交处停止。

目前,超级项目中的“ pull --rebase”会产生合并冲突,因为子模块指针更改存在冲突且无法解决。


  1. 仅本地子模块更改

假设历史记录如上所述,但远程分支不包含子模块更改,则结果为

A(H)---B(I)              F(K)---G(L)  rebased branch
        \               /
         C(I)---D(I)---E(I) remote branch
Run Code Online (Sandbox Code Playgroud)

是可以渴望的。这就是目前 rebase 中发生的情况。

如果给出了递归标志,理想的 git 将生成一个超级项目,如下所示:

A(H)---B(I)               F(K')---G(L')  rebased branch (incl. sub rebase!)
         \               /
          C(I)---D(I)---E(I) remote branch
Run Code Online (Sandbox Code Playgroud)

子模块为:

      J---K---L (old dangeling tip)
     /
H---I               J'---K'---L' Locally rebased branch
     \             /
      M---N---O---P advaced branch
Run Code Online (Sandbox Code Playgroud)

此补丁并未解决此问题,但添加了一个测试,表明此问题会预先失败。


  1. 仅远程子模块更改

假设历史记录如 (1) 所示,只是本地超级项目分支不会触及子模块,则 rebase 已经在超级项目中解决了,没有冲突:

A(H)---B(I)              F(P)---G(P)  rebased branch (no sub changes)
        \               /
         C(N)---D(N)---E(P) remote branch
Run Code Online (Sandbox Code Playgroud)

此补丁中提供的递归标志还会将子模块更新为:

H---I               J'---K'---L' rebased branch
     \             /
      M---N---O---P remote branch
Run Code Online (Sandbox Code Playgroud)

由于 J、K、L 和 J'、K'、L' 均未从超级项目中引用,因此无需重写超级项目提交。


pull --rebase --recursive' '的结论

如果没有本地超级项目更改,则调用“ submodule update --rebase”就足够了,因为这会产生所需的结果。
如果发生冲突,行为与 ' ' 中的行为相同submodule update --recursive,假定是正常的。

该补丁仅实现(3)。


在合并工作流程上:

我们将从变基工作流程中 (1) 中相同的底层 DAG 开始。
所以在理想的世界中,“ pull --merge --recursive”会产生这样的结果:

H---I---J---K---L---X
     \             /
      M---N---O---P
Run Code Online (Sandbox Code Playgroud)

作为X子模块和超级项目中新的合并提交:

A(H)---B(I)---F(K)---G(L)---Y(X)
        \                  /
         C(N)---D(N)---E(P)
Run Code Online (Sandbox Code Playgroud)

然而,不支持动态修改子模块,因此git mergeY(X)容易在单个补丁中生成。事实上git merge根本不知道子模块。

然而,当至少一侧根本不包含涉及子模块的提交时,那么我们不需要对子模块执行合并,但可以通过签出或LP子模块中完成快进。

该策略已在68d03e4a6e(“为子模块实现自动快进合并”,2010-07-07,Git v1.7.3-rc0 -- merge )中实现,因此为了与 rebase 行为保持一致,我们还需要更新工作树子模块的。


在 Git 2.27(2020 年第 2 季度)之前,“ git pull --rebase”在注意到拉动会导致快进之后尝试运行变基,在过去的几年里,由于没有人注意到的错误,不需要变基,也不明智。

请参阅Elijah Newren ( )提交的 fbae70d(2020 年 3 月 27 日)。(由Junio C Hamano 合并 -- --dfdce31 提交中,2020 年 4 月 22 日)newren
gitster

pull:避免同时运行 merge 和 rebase

签署人:伊利亚·纽伦

opt_rebase为真时,我们仍然首先检查是否可以快进。
如果分支是可快进的,那么我们可以避免变基,只使用合并来执行快进逻辑。

然而,当提交 a6d7eb2c7a (" pull: 可选地重新设置子模块(仅远程子模块更改)", 2017-06-23, Git v2.14.0-rc0 -- merge添加了重新设置子模块的功能时,它意外地导致我们运行了两个合并和变基

添加一个标志以避免同时执行这两种操作。

当用户同时拥有两者pull.rebase并将rebase.autosquash其设置为 true 时会发现此情况。

在这种情况下,合并和变基的运行将导致ORIG_HEAD更新两次(并在末尾匹配 HEAD,而不是在变基开始之前匹配),这与预期相反。


git pull --rebase --recurse-submodules”检查了错误范围内的本地更改,并且未能正确运行,该问题已通过 Git 2.30(2020 年第一季度)修复

pull:检查本地子模块修改是否具有正确的范围

自从 ' '在a6d7eb2git pull中学习了 ' ' (:可选地重新设置子模块(仅远程子模块更改),2017-06-23,Git v2.14.0-rc0),我们通过检查修订范围 ' ' 来检查是否有本地子模块修改。--recurse-submodulespullcurr_head --not rebase_fork_point

此检查的目标是,如果正在重新调整本地提交中存在子模块修改,则中止拉取,因为不支持这种情况。

然而,被变基的实际提交范围不是“ rebase_fork_point..curr_head”,正如“ ”中的逻辑get_rebase_newbase_and_upstream所示,它是“ upstream..curr_head”。

如果“ git merge-base --fork-point”中的“ ”调用get_rebase_fork_point未能在当前分支和我们从中提取的远程跟踪分支之间找到分叉点,则“ rebase_fork_point”为空,并且自4d36f88起(submodule:不要将空 OID 传递给 setup_revisions,2018-05- 24、Git v2.18.0-rc1),“ submodule_touches_in_range”检查“ curr_head”及其所有祖先的子模块修改。

由于很可能在此范围内存在子模块修改(实际上是当前分支的整个历史记录),因此git pull --rebase --recurse-submodules如果当前分支和正在拉取的远程跟踪分支之间不存在分叉点,这会阻止 ' ' 成功。
例如,当当前分支是从从未记录在我们正在拉取的远程跟踪分支的引用日志中的提交分叉时,就会发生这种情况,如“分叉点模式的讨论”部分的最后两段所示git-merge-base解释

通过将“upstream”而不是“rebase_fork_point”作为“ excl_oid”参数传递给“ submodule_touches_in_range”来修复此错误。


在 Git 2.32(2021 年第 2 季度)中,使用 null oid 时,sHA-256 转换会对子模块产生影响:

请参阅提交 3dd7146提交 b8505ec提交 71b7672提交 72871b1提交 dd15f4f提交 1422844提交 5a6dce7、提交 0e5e228 、提交5951bf4提交 ab795f0提交 c3b4e4e提交 92e2cab提交 cf09832(2021 年 4 月 26 日),作者:brian m。卡尔森 ( bk2204) .
(由Junio C Hamano 合并 -- gitster--提交 aaa3c80中,2021 年 5 月 10 日)

hash:提供每个算法的空 OID

签字人:brian m. 卡尔森

直到最近,对象 ID 还没有算法成员,只有哈希值。
因此,可以在所有哈希算法之间共享一个空(全零)对象 ID。
现在我们要处理来自多种哈希算法的对象,确保所有对象 ID 都具有正确的算法字段非常重要。

引入每个算法的 null OID,并将其添加到 struct 中hash_algo
还引入一个包装函数,并在我们曾经使用null_oid常量的任何地方使用它。


mig*_*rao 1

在这里进行测试后,子模块中的更改不会阻止您对父模块执行 pull --rebase 操作。因此,要么您在子模块内执行 pull --rebase 并且那里有非隐藏的更改,要么您使用 git submodule add url 添加了子模块,但随后没有提交子模块添加,这将导致父模块拒绝拉取。你能发布 git status 的输出吗?