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

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

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

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

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


当前回答

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

When you run git submodule update, it checks out the specific version of the project, but not within a branch. This is called having a detached head — it means the HEAD file points directly to a commit, not to a symbolic reference. The issue is that you generally don’t want to work in a detached head environment, because it’s easy to lose changes. If you do an initial submodule update, commit in that submodule directory without creating a branch to work in, and then run git submodule update again from the superproject without committing in the meantime, Git will overwrite your changes without telling you. Technically you won’t lose the work, but you won’t have a branch pointing to it, so it will be somewhat difficult to retrieve.


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

参见“git子模块更新—远程vs git pull”。

MindTooth的回答说明了手动更新(不需要本地配置):

git submodule -q foreach git pull -q origin master

在这两种情况下,这将改变子模块的引用(gitlink,父repo索引中的一个特殊条目),你将需要从主repo中添加、提交和推送这些引用。 下次克隆父repo时,它将填充子模块以反映那些新的SHA1引用。

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


为了避免这个问题,当你在子模块目录下工作时,使用git checkout -b work或类似的东西创建一个分支。当您第二次更新子模块时,它仍然会恢复您的工作,但至少您有一个指针可以返回。 切换带有子模块的分支也很棘手。如果你创建了一个新分支,在那里添加了一个子模块,然后切换回一个没有该子模块的分支,你仍然有子模块目录作为未跟踪目录:


我来回答你的问题:

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

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

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

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

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

Git子模块使用两个移动部分实现: .gitmodules文件和 一种特殊的树对象。

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


从git子模块页面

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

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

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

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

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

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

但是,如果你想,出于方便,直接从你的主项目中修改这些子模块,Git允许你这样做,前提是你先将这些子模块的修改发布到它原来的Git repo中,然后提交你的主项目,引用该子模块的新版本。

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

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

你在主项目中引用的特定提交列表定义了你的配置(这就是配置管理的全部内容,包括版本控制系统)

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

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

其他回答

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

When you run git submodule update, it checks out the specific version of the project, but not within a branch. This is called having a detached head — it means the HEAD file points directly to a commit, not to a symbolic reference. The issue is that you generally don’t want to work in a detached head environment, because it’s easy to lose changes. If you do an initial submodule update, commit in that submodule directory without creating a branch to work in, and then run git submodule update again from the superproject without committing in the meantime, Git will overwrite your changes without telling you. Technically you won’t lose the work, but you won’t have a branch pointing to it, so it will be somewhat difficult to retrieve.


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

参见“git子模块更新—远程vs git pull”。

MindTooth的回答说明了手动更新(不需要本地配置):

git submodule -q foreach git pull -q origin master

在这两种情况下,这将改变子模块的引用(gitlink,父repo索引中的一个特殊条目),你将需要从主repo中添加、提交和推送这些引用。 下次克隆父repo时,它将填充子模块以反映那些新的SHA1引用。

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


为了避免这个问题,当你在子模块目录下工作时,使用git checkout -b work或类似的东西创建一个分支。当您第二次更新子模块时,它仍然会恢复您的工作,但至少您有一个指针可以返回。 切换带有子模块的分支也很棘手。如果你创建了一个新分支,在那里添加了一个子模块,然后切换回一个没有该子模块的分支,你仍然有子模块目录作为未跟踪目录:


我来回答你的问题:

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

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

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

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

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

Git子模块使用两个移动部分实现: .gitmodules文件和 一种特殊的树对象。

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


从git子模块页面

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

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

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

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

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

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

但是,如果你想,出于方便,直接从你的主项目中修改这些子模块,Git允许你这样做,前提是你先将这些子模块的修改发布到它原来的Git repo中,然后提交你的主项目,引用该子模块的新版本。

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

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

你在主项目中引用的特定提交列表定义了你的配置(这就是配置管理的全部内容,包括版本控制系统)

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

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

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

git submodule -q foreach git pull -q origin master

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

处理——rebase vs.——merge选项:

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

Git子模块更新

你处于无头状态,所以你在这一点上所做的任何提交都很难返回。那么,您已经开始在子模块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,这通常正是你想要的。

(这句话摘自这个答案。)