子模块和'git pull --rebase'

时间:2011-07-22 14:45:12

标签: git macos git-submodules git-pull

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

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

我们得到:

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

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

谢谢! 詹姆斯

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

我们无法在超级或子模块中使用'git pull --rebase'

要确保涉及子模块,请使用Git 2.14(2017年第三季度,OP提出问题的第六年)或更多带有“ git pull --rebase --recurse-submodules ”的单词,后者学会了在子模块以更新为基础。

请参见commit e8906a9commit a6d7eb2(2017年6月27日)和commit 8c69832commit 886dc15Stefan Beller (stefanbeller)(2017年6月23日)。
(由Junio C Hamano -- gitster --commit c9c63ee中合并,2017年7月13日)

pull:可以选择对子模块进行重新设置基准(仅对远程子模块进行更改)

签名人:布兰登·威廉姆斯
签名人:Stefan Beller

在提供“ --recurse-submodules”时,教pull可选地更新子模块。

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

在变基工作流上:

  1. 双方都更改了子模块

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

H---I---J---K---L local branch
     \
      M---N---O---P remote branch

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

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

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

当前,超级项目中的“ pull --rebase”会导致合并冲突,因为子模块指针的更改相互冲突且无法解决。


  1. 仅本地子模块更改

假定历史与上述相同,只是远程分支将不包含子模块更改,然后结果为

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

是需要的。这是当前在变基中发生的情况。

如果给定了递归标志,理想的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

此修补程序中显示的recurse标志将另外将子模块更新为:

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根本不了解子模块。

但是,当至少一侧完全不包含涉及子模块的提交时,我们就不需要为子模块执行合并,而是可以通过检出L或{ {1}}在子模块中。

此策略已在68d03e4a6e中实现(“为子模块实现自动快速转发合并”,2010-07-07,Git v1.7.3-rc0-merge),因此可以进行调整利用rebase行为,我们还需要更新子模块的工作树。


在Git 2.27(2020年第2季度)之前,“ P”试图运行重新设置,即使在注意到拉动导致快速前进且在过去几年中由于不需要重新设置也不明智之举没有人注意到的错误。

请参见commit fbae70dElijah Newren (newren)(2020年3月27日)。
(由Junio C Hamano -- gitster --commit dfdce31中合并,2020年4月22日)

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

签名人:伊利亚·纽伦

git pull --rebase为true时,我们仍将首先检查是否可以快进。
如果分支是可快速转发的,则我们可以避免重新设置基础,而只需使用merge即可执行快速转发逻辑。

但是,当commit a6d7eb2c7a(“ opt_rebase:可选地对子模块进行基础设置(仅对远程子模块进行更改)”时,2017-06-23,Git v2.14.0-rc0-merge添加了对子模块进行基础设置的功能,这偶然导致我们同时运行合并和基础操作

添加标志以避免两者同时发生。

这是在用户将pullpull.rebase都设置为true时发现的。

在这种情况下,合并和重新设置的运行都会导致rebase.autosquash被更新两次(并且与HEAD匹配,而不是重新启动重新提交之前的提交),这超出了预期。


ORIG_HEAD”检查了本地更改 Git 2.30(Q1 2020)中已解决的错误范围内并未能正确运行。

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

自'git pull --rebase --recurse-submodules'在a6d7eb2中学习'git pull' (--recurse-submodules :(可选)对子模块进行基准化(仅对远程子模块进行更改), 2017年6月23日,Git v2.14.0-rc0),我们检查是否有本地子模块修改 检查修订范围“ pull”。

此检查的目的是如果有子模块,则中止拉动 因为这种情况是 不支持。

但是,重新提交的实际提交范围不是 'curr_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”为空,并且由于4d36f88rebase_fork_point:请勿将空OID传递给setup_revisions,2018-05-24,Git v2.18.0-rc1),因此“ {{1} }'检查'submodule'及其所有祖先以进行子模块修改。

因为很有可能在此子模块中进行了修改 范围(实际上是当前分支的整个历史记录), 如果没有,阻止“ submodule_touches_in_range”成功 分支点位于当前分支和远程跟踪之间 分支被拉动。
例如,当当前分支是从一个从未提交到远程跟踪分支的刷新日志中的提交中分叉的,例如last two paragraphs of the "Discussion on fork-point mode" section in git-merge-base explain时,就会发生这种情况。

通过传递“上游”而不是“ rebase_fork_point”作为错误来修复此错误。 'curr_head的'git pull --rebase --recurse-submodules'自变量。