git子模块更新

问题描述 投票:219回答:4

我不清楚以下是什么意思(来自git submodule update docs):

......除非指定--rebase--merge,否则将使子模块HEAD分离...

--rebase / --merge如何改变事物?

我的主要用例是有一堆中央存储库,我将通过子模块嵌入到其他存储库中。我希望能够改进这些中央回购,直接在他们的原始位置,或从他们的嵌入回购(通过子模块使用它们的那些)。

  • 从这些子模块中,我可以创建分支/修改并使用推/拉,就像我在常规回购中一样,或者有什么需要谨慎的吗?
  • 我如何将子模块引用的提交从say(tagged)1.0提升到1.1(即使原始repo的头部已经是2.0),或者选择使用哪个分支的提交?
git git-submodules
4个回答
284
投票

这个GitPro page很好地总结了git子模块更新的结果

运行git submodule update时,它会检出项目的特定版本,但不会检出分支。这称为具有分离的头 - 这意味着HEAD文件直接指向提交,而不是指向符号引用。 问题在于,您通常不希望在分离的头部环境中工作,因为很容易丢失更改。 如果您执行初始子模块更新,请在该子模块目录中提交而不创建要运行的分支,然后再从超级项目再次运行git子模块更新而不提交,Git将在不告知您的情况下覆盖您的更改。从技术上讲,你不会失去工作,但你不会有一个分支指向它,所以它将有点难以检索。


注意2013年3月:

如“git submodule tracking latest”中所述,现在的子模块(git1.8.2)可以跟踪分支。

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

见“git submodule update --remote vs git pull”。

MindToothanswer说明了手动更新(没有本地配置):

git submodule -q foreach git pull -q origin master

在这两种情况下,这将改变子模块引用(gitlinkspecial entry in the parent repo index),并且您将需要添加,提交和推送来自主repo的所述引用。 下次您将克隆该父repo时,它将填充子模块以反映这些新的SHA1引用。

本答案的其余部分详细介绍了经典的子模块功能(引用固定提交,这是子模块概念背后的所有要点)。


要避免此问题,请在使用git checkout -b work或等效工作的子模块目录中创建分支。当您第二次执行子模块更新时,它仍将恢复您的工作,但至少您有一个指针可以返回。

切换带有子模块的分支也很棘手。如果您创建一个新分支,在那里添加一个子模块,然后切换回没有该子模块的分支,您仍然将子模块目录作为未跟踪的目录:


那么,回答你的问题:

我可以创建分支/修改并使用推/拉,就像我在常规回购中一样,或者有什么需要谨慎的吗?

您可以创建分支并推送修改。

警告(来自Git Submodule Tutorial):在将更改发布(推送)到引用它的超级项目之前,始终发布(推送)子模块更改。如果您忘记发布子模块更改,则其他人将无法克隆存储库。

我如何将子模块引用的提交从say(tagged)1.0推进到1.1(即使原始repo的头部已经是2.0)

页面“Understanding Submodules”可以提供帮助

Git子模块使用两个移动部件实现:

  • .gitmodules文件和
  • 一种特殊的树对象。

这些一起对特定存储库的特定修订进行三角测量,该存储库被检出到项目中的特定位置。


来自git submodule page

您无法从主项目中修改子模块的内容

100%正确:您无法修改子模块,只能参考其中一个提交。

这就是为什么当您从主项目中修改子模块时,您:

  • 需要提交并推送子模块(到上游模块),和
  • 然后进入你的主项目,然后重新提交(为了让那个主项目引用你刚刚创建和推送的新子模块提交)

子模块使您可以进行component-based approach开发,其中主项目仅引用其他组件的特定提交(此处“声明为子模块的其他Git存储库”)。

子模块是另一个Git存储库的标记(提交),它不受主项目开发周期的约束:它(“其他”Git存储库)可以独立发展。 主要项目取决于其他任何需要提交的回购。

但是,如果您想方便地直接从主项目中修改其中一个子模块,Git允许您这样做,前提是您首先将这些子模块修改发布到其原始Git仓库,然后提交您的主项目引用所述子模块的新版本。

但主要的想法仍然是:引用以下特定组件:

  • 有自己的生命周期
  • 有自己的标签集
  • 有自己的发展

您在主项目中引用的特定提交列表定义了您的configuration(这是配置管理的全部内容,仅仅是Version Control System

如果一个组件真的可以与你的主项目同时开发(因为对主项目的任何修改都涉及修改子目录,反之亦然),那么它将不再是一个“子模块”,而是一个子树合并(也在问题Transferring legacy code base from cvs to distributed repository中提出),将两个Git repo的历史联系在一起。

这有助于理解Git子模块的真实性质吗?


131
投票

要更新每个子模块,可以调用以下命令。 (根据回购。)

git submodule -q foreach git pull -q origin master

您可以删除-q选项以遵循整个过程。


18
投票

要解决--rebase vs --merge选项:

假设您有超级回购A和子模块B,并希望在子模块B中做一些工作。您已完成作业并且在调用后知道

git submodule update

你处于无HEAD状态,所以你在这一点上做的任何提交都很难回复。所以,你已经开始在子模块B中的新分支上工作了

cd B
git checkout -b bestIdeaForBEver
<do work>

与此同时,项目A中的其他人已经确定最新和最好的B版本确实是应得的。出于习惯,您可以合并最近的更改并更新子模块。

<in A>
git merge develop
git submodule update

哦,不!你又回到了无头状态,可能是因为B现在指向与B的新提示或其他提交相关联的SHA。如果只有你:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

现在B的最佳创意已经重新定位到新的提交,更重要的是,你仍然在B的开发分支上,而不是无头状态!

(--merge会将来自beforeUpdateSHA的更改合并到afterUpdateSHA到您的工作分支,而不是将更改重新定义到afterUpdateSHA。)


5
投票

Git 1.8.2提供了一个新的选项--remote,可以实现这种行为。运行

git submodule update --rebase --remote

将从每个子模块的上游获取最新的更改,将它们重新绑定,并检查子模块的最新版本。正如the docs所说:

--remote

此选项仅对update命令有效。不使用超级项目记录的SHA-1来更新子模块,而是使用子模块的远程跟踪分支的状态。

这相当于在每个子模块中运行git pull,这通常正是您想要的。

(从this answer复制)

© www.soinside.com 2019 - 2024. All rights reserved.