Git 子模块更新

发布于 2024-08-16 12:00:39 字数 518 浏览 7 评论 0原文

我不清楚以下含义(来自 Git 子模块更新 文档):

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

--rebase 是如何实现的/--merge 改变什么?

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

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

I'm not clear on what the following means (from the Git submodule update documentation):

...will make the submodules HEAD be detached, unless --rebase or --merge is specified...

How does --rebase/--merge change things?

My main use case is to have a bunch of central repositories, which I will embed via submodules into other repositories. I would like to be able to improve on these central repositories, either directly in their original location, or from within their embedding repositories (the ones that use them via submodule).

  • From within these submodules, can I create branches/modifications and use push/pull just like I would in regular repositories, or are there things to be cautious about?
  • How would I advance the submodule referenced commit from say (tagged) 1.0 to 1.1 (even though the head of the original repository is already at 2.0), or pick which branch's commit is used at all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

画中仙 2024-08-23 12:00:39

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

当您运行git submodule update时,它会检查项目的特定版本,但不在分支内。这称为具有分离的头 - 这意味着 HEAD 文件直接指向提交,而不是符号引用。
问题是您通常不想在独立的头脑环境中工作,因为很容易丢失更改
如果您进行初始子模块更新,在该子模块目录中提交而不创建要工作的分支,然后从超级项目再次运行 git submodule update 而不同时提交,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

请参阅“git submodule update --remotegit pull” 。

MindTooth答案 说明手动更新(无需本地配置):

git submodule -q foreach git pull -q origin master

在这两种情况下,这都会更改子模块引用(gitlink父存储库索引中的特殊条目),您需要添加、提交和推送来自主存储库的引用。
下次您克隆该父存储库时,它将填充子模块以反映这些新的 SHA1 引用。

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


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

切换带有子模块的分支也可能很棘手。如果您创建一个新分支,在其中添加一个子模块,然后切换回没有该子模块的分支,则子模块目录仍然是未跟踪的目录:


因此,回答您的问题:

我可以像在常规存储库中一样创建分支/修改并使用推/拉吗?或者有什么需要注意的吗?

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

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

如何将子模块引用的提交从(标记的)1.0 推进到 1.1(即使原始存储库的头部已经在 2.0)

页面“了解子模块" 可以提供帮助

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

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

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


来自 git 子模块页面

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

100% 正确地修改子模块的内容:您无法修改子模块,只能引用其提交之一。

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

  • 需要在子模块内提交并推送(到上游模块),然后
  • 进入主项目,并且重新提交(为了使该主项目引用您刚刚创建并推送的新子模块提交)

子模块使您能够拥有基于组件的方法开发,其中主项目仅引用其他组件的特定提交(此处“声明为子项目的其他 Git 存储库”) -模块”)。

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

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

但主要思想仍然是:引用特定组件,这些组件:

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

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

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

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

This GitPro page does summarize the consequence of a git submodule update nicely

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.


Note March 2013:

As mentioned in "git submodule tracking latest", a submodule now (git1.8.2) can track a branch.

# 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

See "git submodule update --remote vs git pull".

MindTooth's answer illustrate a manual update (without local configuration):

git submodule -q foreach git pull -q origin master

In both cases, that will change the submodules references (the gitlink, a special entry in the parent repo index), and you will need to add, commit and push said references from the main repo.
Next time you will clone that parent repo, it will populate the submodules to reflect those new SHA1 references.

The rest of this answer details the classic submodule feature (reference to a fixed commit, which is the all point behind the notion of a submodule).


To avoid this issue, create a branch when you work in a submodule directory with git checkout -b work or something equivalent. When you do the submodule update a second time, it will still revert your work, but at least you have a pointer to get back to.

Switching branches with submodules in them can also be tricky. If you create a new branch, add a submodule there, and then switch back to a branch without that submodule, you still have the submodule directory as an untracked directory:


So, to answer your questions:

can I create branches/modifications and use push/pull just like I would in regular repos, or are there things to be cautious about?

You can create a branch and push modifications.

WARNING (from Git Submodule Tutorial): Always publish (push) the submodule change before publishing (push) the change to the superproject that references it. If you forget to publish the submodule change, others won't be able to clone the repository.

how would I advance the submodule referenced commit from say (tagged) 1.0 to 1.1 (even though the head of the original repo is already at 2.0)

The page "Understanding Submodules" can help

Git submodules are implemented using two moving parts:

  • the .gitmodules file and
  • a special kind of tree object.

These together triangulate a specific revision of a specific repository which is checked out into a specific location in your project.


From the git submodule page

you cannot modify the contents of the submodule from within the main project

100% correct: you cannot modify a submodule, only refer to one of its commits.

This is why, when you do modify a submodule from within the main project, you:

  • need to commit and push within the submodule (to the upstream module), and
  • then go up in your main project, and re-commit (in order for that main project to refer to the new submodule commit you just created and pushed)

A submodule enables you to have a component-based approach development, where the main project only refers to specific commits of other components (here "other Git repositories declared as sub-modules").

A submodule is a marker (commit) to another Git repository which is not bound by the main project development cycle: it (the "other" Git repo) can evolves independently.
It is up to the main project to pick from that other repo whatever commit it needs.

However, should you want to, out of convenience, modify one of those submodules directly from your main project, Git allows you to do that, provided you first publish those submodule modifications to its original Git repo, and then commit your main project refering to a new version of said submodule.

But the main idea remains: referencing specific components which:

  • have their own lifecycle
  • have their own set of tags
  • have their own development

The list of specific commits you are refering to in your main project defines your configuration (this is what Configuration Management is all about, englobing mere Version Control System)

If a component could really be developed at the same time as your main project (because any modification on the main project would involve modifying the sub-directory, and vice-versa), then it would be a "submodule" no more, but a subtree merge (also presented in the question Transferring legacy code base from cvs to distributed repository), linking the history of the two Git repo together.

Does that help understanding the true nature of Git Submodules?

木有鱼丸 2024-08-23 12:00:39

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

git submodule -q foreach git pull -q origin master

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

To update each submodule, you could invoke the following command (at the root of the repository):

git submodule -q foreach git pull -q origin master

You can remove the -q option to follow the whole process.

倾城泪 2024-08-23 12:00:39

要解决 --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 会将 beforeUpdateSHA 到 afterUpdateSHA 的更改合并到您的工作分支中,而不是将更改重新调整到 afterUpdateSHA 上。)

To address the --rebase vs. --merge option:

Let's say you have super repository A and submodule B and want to do some work in submodule B. You've done your homework and know that after calling

git submodule update

you are in a HEAD-less state, so any commits you do at this point are hard to get back to. So, you've started work on a new branch in submodule B

cd B
git checkout -b bestIdeaForBEver
<do work>

Meanwhile, someone else in project A has decided that the latest and greatest version of B is really what A deserves. You, out of habit, merge the most recent changes down and update your submodules.

<in A>
git merge develop
git submodule update

Oh noes! You're back in a headless state again, probably because B is now pointing to the SHA associated with B's new tip, or some other commit. If only you had:

git merge develop
git submodule update --rebase

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

Now that best idea ever for B has been rebased onto the new commit, and more importantly, you are still on your development branch for B, not in a headless state!

(The --merge will merge changes from beforeUpdateSHA to afterUpdateSHA into your working branch, as opposed to rebasing your changes onto afterUpdateSHA.)

难如初 2024-08-23 12:00:39

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

git submodule update --rebase --remote

将从每个子模块的上游获取最新更改,重新设置它们,并检查子模块的最新版本。正如 文档 所说:

--远程

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

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

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

Git 1.8.2 features a new option ,--remote, that will enable exactly this behavior. Running

git submodule update --rebase --remote

will fetch the latest changes from upstream in each submodule, rebase them, and check out the latest revision of the submodule. As the documentation puts it:

--remote

This option is only valid for the update command. Instead of using the superproject’s recorded SHA-1 to update the submodule, use the status of the submodule’s remote-tracking branch.

This is equivalent to running git pull in each submodule, which is generally exactly what you want.

(This was copied from this answer.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文