【问题标题】:How do I "git add" a modified submodule into the main module?如何将修改后的子模块“git add”到主模块中?
【发布时间】:2020-06-28 23:51:45
【问题描述】:

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

# 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)
...

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

主模块和子模块都在同一个分支上。

【问题讨论】:

  • 嗨格兰特!我可以看到您在这里投了反对票,但没有评论为什么这太糟糕了。我自己对子模块不是很熟悉,但每次我必须使用它们时,我都知道它们有自己的own commands。我怀疑你需要一个 git submodule add 或其他东西。
  • 请注意,子模块不是在一个分支上。它是一个特定的提交,作为一个分离的 HEAD。如果该提交有一个分支名称,这会使您的工作更轻松:当您进入子模块时,使用git checkout <branch-name> 重新附加其HEAD,这不会更改 commits,因为已分离HEAD 已经在同一个提交中。

标签: git git-submodules git-add


【解决方案1】:

让我们从游泳池的最深处开始。这个:

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

表明你的超级项目 Git 做了一个:

(cd deps/gr-d13; git status)

找出子模块存储库的状态,当它这样做时,它的(子模块的)工作树有被修改的文件和未被跟踪的文件。

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

一旦你在子模块中有一个新的提交,你就可以让超级项目引用那个新的提交。为此,请返回超级项目,然后运行 ​​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 格式存储,作为提交快照的一部分。)与任何 Git 存储库一样,当您签出提交时,其文件进入 为该存储库创建索引,然后从那里将它们复制出来,并扩展为有用的形式,到工作树,以便您可以查看和处理/使用它们。

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

您可以随时使用:

cd deps/gr-d13

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


1在旧版本的 Git 中,.git 将是一个实际目录,包含子模块的存储库数据库(即,所有不是工作树的内容)。在现代 Git 中,.git 将是一个普通文件。 Git 现在将子模块存储库数据库“吸收”到超级项目中,位于包含超级项目数据的 .git 下的目录中。


使用子模块和推送/获取

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

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

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

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

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

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

【讨论】:

  • 非常感谢您提供的信息丰富的回答。我早就想接受了。一旦我得到那个 git 并不太关心分支(并且子模块不能与主模块在同一个分支上),它只想要子模块的提交,一切都到位了。 (如果我弄错了,请随时纠正我的概要)。你为我节省了很多时间。
猜你喜欢
  • 2017-10-05
  • 2021-01-31
  • 2015-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多