Git子模块更新

我不清楚以下是什么意思(来自Git子模块更新文档):

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

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

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

  • 从这些子模块中,我是否可以创建分支/修改,并像在常规存储库中那样使用推/拉,或者是否有需要注意的事情?
  • 我将如何将子模块引用提交从说(标记)1.0推进到1.1(即使原始存储库的头已经在2.0),或者选择哪个分支的提交被使用?
329593 次浏览

GitPro页面很好地总结了git子模块更新的结果

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

2013年3月:

正如在"Git子模块跟踪最新"中提到的,现在子模块(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

看到“__ABC0 vs git pull”。

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

git submodule -q foreach git pull -q origin master
在这两种情况下,这将改变子模块的引用(< a href = " https://stackoverflow.com/a/16581096/6309 " > gitlink < / >,一个父回购索引中的特殊条目),你将需要从主repo中添加、提交和推入这些引用 下次克隆父repo时,它将填充子模块以反映那些新的SHA1引用

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


为了避免这个问题,当你在子模块目录下工作时,使用git checkout -b work或类似的东西创建一个分支。当您第二次更新子模块时,它仍然会恢复您的工作,但至少您有一个指针可以返回。

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


我来回答你的问题:

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

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

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

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

页面“理解子”可以提供帮助

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

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

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


Git子模块页面

不能在主项目内修改子模块的内容

100%正确:你不能修改子模块,只能引用它的一个提交。

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

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

子模块允许你进行基于组件的方法 .开发,其中主项目只引用其他组件的特定提交(这里是“声明为子模块的其他Git存储库”)。

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

然而,如果你想出于方便直接从你的主项目中修改这些子模块之一,Git允许你这样做,只要你第一个将这些子模块的修改发布到它的原始Git repo中,并且然后提交你的主项目,引用该子模块的版本。

但主要思想仍然是:引用特定的组件:

  • 有自己的生命周期
  • 有自己的一套标签吗
  • 有自己的发展

你在主项目中引用的特定提交列表定义了你的899428年< a href = " https://stackoverflow.com/questions/899373/transferring-legacy-code-base-from-cvs-to-distributed-repository-e-g-git-or-mer/899428 " > < / >配置(这就是< em > < / em >配置管理的全部内容,只包含版本控制系统)

如果一个组件真的可以作为你的主项目同时开发(因为对主项目的任何修改都会涉及修改子目录,反之亦然),那么它将不再是一个“子模块”,而是一个子树合并(也在问题将遗留代码库从cvs转移到分布式存储库中提出),将两个Git回购的历史链接在一起。

这有助于理解Git子模块的本质吗?

要更新每个子模块,您可以调用以下命令(在存储库的根):

git submodule -q foreach git pull -q origin master

你可以删除q选项来跟踪整个过程。

处理--rebase--merge选项:

假设您有超级存储库A和子模块B,并希望在子模块B中做一些工作。您已经完成了作业,并且在调用后知道了这一点

git submodule update

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

cd B
git checkout -b bestIdeaForBEver
<do work>

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

<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将从updatesha之前到updatesha之后的更改合并到你的工作分支中,而不是将更改重新基于updatesha之后。)

Git 1.8.2提供了一个新选项--remote,它将启用这种行为。运行

git submodule update --rebase --remote

将从每个子模块的上游获取最新的更改,将它们重新赋基,并检出子模块的最新修订。正如的文档所说:

——远程

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

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

(这是从这个答案复制的。)