我如何 "git add" 将修改后的子模块添加到主模块中?

How do I "git add" a modified submodule into the main module?

我修改、添加、提交并将更改推送到子模块,然后转到主模块目录 运行:

# git status
...
Changes not staged for commit:
...
modified:   deps/gr-d13 (modified content, untracked content)
...

# git add deps/gr-d13
(no errors)
# git status
...
Changes not staged for commit:
...
modified:   deps/gr-d13 (modified content, untracked content)
...

和以前一模一样。我的子模块没有上演。为什么不呢?

主子模块在同一个b运行ch.

让我们先从游泳池的深处潜入水中开始。这个:

modified:   deps/gr-d13 (modified content, untracked content)

表示您的超级项目 Git 做了一个:

(cd deps/gr-d13; git status)

找出子模块存储库的状态,当它出现时,它的(子模块的)工作树包含已修改的文件和未跟踪的文件。

如果您希望提交这些文件,您需要自己进入子模块存储库,并像使用任何 Git 存储库一样使用它。请记住,它当前处于 detached HEAD 模式,并检查了特定的提交。此提交可能有也可能没有与之关联的分支名称。如果没有,请记住您需要做什么。

一旦你在子模块中有了新的提交,你就可以让超级项目引用那个新的提交。为此,return 到超级项目,运行 git add deps/gr-d13。这将告诉超级项目 Git 做 (cd deps/gr-d13; git rev-parse HEAD) 来找到正确的提交哈希 ID,然后在超级项目的索引中记录该哈希 ID。

背景

请记住,子模块只不过是第二个 Git 存储库。您的(顶级)Git 存储库现在是一个 超级项目 。在你的超级项目中,你所做的每个提交都列出了两件事:

  • 子模块存储库的路径名,在本例中,deps/gr-d13
  • 您的超级项目 Git 应该使用的哈希 ID:

    (cd $submodule; git checkout $hash)
    

    以便强制子模块 Git 在指定提交处处于 分离 HEAD 模式。

(超级项目 应该 也有一个 .gitmodules 文件,其中包含超级项目的新克隆需要的信息,以便 运行 git clone 创建子模块存储库的命令。这个文件也应该在每个提交中。一旦子模块存储库存在,Git 不再需要 .gitmodules 文件来获取此信息。)

您在 工作树 中看到的文件 不是 已提交的文件。 (提交的文件以特殊的、压缩的、只读的、Git-only 格式存储,作为提交快照的一部分。)就像在任何 Git 存储库中一样,当您签出提交时,它的文件进入该存储库的 index,然后从那里将它们复制出来,并扩展为有用的形式,到工作树,以便您可以查看和处理 /和他们在一起。

您的超级项目内部没有任何子模块提交,它只有子模块提交的 哈希 ID。但是,您的超级项目存储库的工作树确实有一个目录(或文件夹,如果您更喜欢该术语),其中包含 .git1 和工作树子模块。这意味着子模块的工作树是超级项目工作树的子目录。

您可以随时使用:

cd deps/gr-d13

自己进入子模块仓库。如果这样做,您就可以像使用任何存储库一样使用它。它有提交、HEAD、索引和工作树,就像任何存储库一样。这个子模块存储库的唯一特别之处在于有一个外部存储库,偶尔(当被告知时)会对子模块执行 cd 并 运行 git checkout <hash> 强制它进入分离的 HEAD在指定的提交处再次模式。


1在 Git 的旧版本中,这个 .git 将是一个实际目录,包含子模块的存储库数据库(即,所有不是工作树)。在现代 Git 中,这个 .git 将是一个普通文件。 Git 现在 "absorbs" 子模块存储库数据库进入超级项目,在 .git 下的目录中保存超级项目数据。


使用子模块和 push/fetch

使用常规 Git 存储库通常有点复杂,因为 Git 是一个 分布式 版本控制系统。这意味着您不仅需要管理 您的 存储库,您还需要担心一些其他存储库,例如 GitHub 上的存储库,它主要包含相同的提交,但是有自己的分支名称。

换句话说,要使用一个 Git 存储库,您实际上是在使用 两个 Git 存储库:您的和另一个在 origin。您的工作量增加了一倍(或更糟,因为它们只是松散地协调)。

当您将子模块添加到组合中时,您的工作量会再次加倍(或更糟),因为子模块 一个 Git 存储库,因此,也有一个origin。所以现在您正在使用 四个 Git 个存储库。你的和原来的那个是无论如何协调的;你必须协调你的与你的子模块存储库。但是您的子模块存储库也与 its origin.

协调

因为您的超级项目存储库不断分离子模块中的 HEAD,实际上在子模块中执行任何 work 都需要输入它,重新附加其 HEADits 分支名称之一(或者在适当的情况下创建一个新的分支名称),然后才开始工作并进行新的提交。一旦您完成了这些新的提交,您可能想用您的超级项目来测试它们,也许是通过在超级项目中进行提交。如果它们不成功,您可能需要撤消所有这些提交。

(如果愿意,您可以在超级项目和子模块存储库中处理未提交的更改。根据您的任务和要求,这可能更容易。)

无论如何,一旦子模块提交存在且正确,您将希望使用子模块中的 git push 将这些提交发送到它的 origin。您可以在将超级项目更新为 use 这些提交之前或之后执行此操作。请记住,如果您首先更新您的超级项目,您应该确保在您从超级项目 git push 之前从子模块 git push 。原因是任何其他想要您的新超级项目提交的人也将需要您的新子模块提交。