4

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

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

我们得到:

james:libraries james$ git pull --rebase
Cannot pull with rebase: You have unstaged changes.
Please commit or stash them.

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

谢谢!詹姆士

4

2 回答 2

4

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

为了确保涉及子模块,请使用 Git 2.14(2017 年第三季度,在 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: 可选地 rebase 子模块(仅远程子模块更改)

签字人: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

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

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

在理想的世界中,这将重新设置子模块并重写超级项目指向的子模块指针,从而使超级项目看起来像

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

子模块为:

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

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

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


  1. 仅本地子模块更改

假设历史如上,除了远程分支不包含子模块更改,则结果为

A(H)---B(I)              F(K)---G(L)  rebased branch
        \               /
         C(I)---D(I)---E(I) remote branch

是渴望的。这就是当前在 rebase 中发生的事情。

如果给出递归标志,理想的 git 将产生一个超级项目:

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

子模块为:

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

这个补丁没有解决这个问题,但是添加了一个测试,它预先失败了。


  1. 仅远程子模块更改

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

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

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

H---I               J'---K'---L' rebased branch
     \             /
      M---N---O---P remote branch

由于 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

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

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

但是,不支持动态修改子模块,git merge这样Y(X)在单个补丁中就不容易生成。实际上git merge根本不知道子模块。

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

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


在 Git 2.27(2020 年第二季度)之前," git pull --rebase" 尝试运行 rebase,即使在注意到 pull 导致快进并且不需要 rebase 也不明智之后,在过去的几年中,由于没有人注意到的错误。

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

pull: 避免同时运行合并和变基

签字人:以利亚·纽伦

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

但是,当commit a6d7eb2c7a (" pull: optional rebase submodules (remote submodule changes only)", 2017-06-23, Git v2.14.0-rc0 -- merge )添加了 rebase 子模块的能力时,它意外地导致我们同时运行合并和变基

添加一个标志以避免两者都做。

当用户同时拥有这两者pull.rebaserebase.autosquash设置为 true 时,就会发现这一点。

在这种情况下,merge 和 rebase 的运行将导致ORIG_HEAD更新两次(并在最后匹配 HEAD 而不是在 rebase 开始之前的提交),这与预期相反。


" git pull --rebase --recurse-submodules" 检查了错误范围内的本地更改,并且在应该正确运行时未能正确运行,这已在 Git 2.30 (Q1 2020) 中修复

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

自从在a6d7eb2git pull中学习了 ' ' (:可选地 rebase 子模块(仅远程子模块更改),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' 为 null 并且自4d36f88 ( submodule: 不要将 null OID 传递给 setup_revisions, 2018-05- 24, Git v2.18.0-rc1), ' submodule_touches_in_range' 检查 ' curr_head' 及其所有祖先的子模块修改。

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

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


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

提交 3dd7146提交 b8505ec提交 71b7672提交 72871b1提交 dd15f4f提交 1422844提交 5a6dce7提交0e5e228提交 5951bf4提交 ab795f0提交 c3b4e4e,提交 92e2cab 4 月 2 日brian 2098年2 月 2 日 卡尔森 ( bk2204) .
(由Junio C Hamano 合并 -- gitster--提交 aaa3c80中,2021 年 5 月 10 日)

hash:提供每个算法的空 OID

签字人:brian m. 卡尔森

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

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

于 2020-04-26T13:31:06.430 回答
1

在这里测试之后,对子模块进行更改并不会阻止您在父模块上执行 pull --rebase 。所以要么你在子模块内部做 pull --rebase 并且你在那里有非隐藏的更改,或者你可能使用 git submodule add url 添加了子模块但你没有提交子模块添加,这将导致父级拒绝拉. 您可以发布 git status 的输出吗?

于 2012-03-09T20:20:16.837 回答