我在另一个模块中有一个git子模块,是通过git submodule add <...>
(从父存储库发出的命令)添加的,因此.gitmodules
文件是在父存储库中自动生成的。
假设我对子模块进行了更改(编辑:,并且不提交这些更改),然后返回到父级并执行git add -A
,然后git status
,上面写着“未上演提交更改:子模块目录名称 ...等”。
我以为git会读取.gitmodules
文件(由父git生成!),实现它的git子模块目录,因此当我向父文件询问其状态时不提及其未暂存状态?
答案 0 :(得分:3)
这里发生的是您的子模块存储库位于与超级项目中记录的哈希ID不同的提交上。在超级项目中运行的git status
会告诉您这一点,而无需更改它,而git add -A
显然也没有更改。
这最后一部分似乎是错误的。当我做类似的事情,然后使用git add -A
时,我得到:
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: [submodule path]
如果我随后再运行两个命令,它会按照我的预期返回:
$ git reset
Unstaged changes after reset:
M [submodule path]
$ git submodule update
Submodule path [path]: checked out '[hash]'
$ git status
On branch ...
nothing to commit, working tree clean
(我怀疑您在子模块中进行了一些更改,但从未在此处进行过更改。)
我们有一个名为 superproject 的Git存储库,它控制着另一个名为 submodule 的存储库。超级项目实际上具有三个单独的控制旋钮,每个提交中都存在一个控制旋钮,因此也可以在 index 中找到(因为索引控制着要进入 next 提交)。
您提到的文件.gitmodules
是这些控制旋钮之一。如果子模块尚未git clone
d,它将告诉超级项目如何克隆子模块。克隆子模块后,其主要工作就完成了。
第二个是您的.git/config
文件。它包含从.gitmodules
文件中复制的信息,如果.gitmodules
文件不完全适合您的目的(可能与负责{ {1}}文件)。 .gitmodules
中的任何设置都会覆盖.git/config
中的设置。否则,这两个放置设置在本质上是等效的。
最后一个是导致问题的原因。为了使子模块能够在您的工作树中检出,从而对您有用,控制超级项目的Git旋转了第二组Git命令。通常,您可以运行:
.gitmodules
要检出子模块(尽管如果使用git submodule update --init
,Git会为您完成此操作)。
在这一点上,超级项目Git已经建立了一个具有正确路径的几乎为空的目录。 (该目录包含一个git clone --recursive
文件,该文件为克隆存储库的路径命名,或者在过去或者使用旧样式的向后兼容模式时,都包含实际的.git
目录本身。)超级项目Git { {1}}进入此目录并告诉子模块Git:
.git
一旦发生这种情况,路径中就会充满从ID为 chdir
的提交中提取的文件,这大部分会使外部Git(超项目)与文件“完成”。但是有一个副作用,因为子模块本身就是一个完整的Git存储库,包含了这一切。
尤其是,子项目具有自己的git checkout hash
。现在hash
已被分离,并且子模块的存储库的当前提交是 HEAD
,因此它位于子模块的索引和工作树中,这当然是我们想要的:子模块的工作树是超级项目中所有子模块文件所在的路径。
但是有一个有趣的问题要回答:超级项目Git在哪里获得哈希ID?答案是:它存储在每个快照中-嗯,每个快照使用子模块-在超级项目中,每个快照都具有每个文件的完整副本。为此,超级项目的索引包含类型为 gitlink 的特殊条目。
每当超级项目告诉子模块Git时,superproject索引中的gitlink条目就会告诉超级项目哪个哈希ID赋予子模块Git:签出一些特定的提交。
如果您手动导航到子模块中,并且HEAD
是分支名称或任何其他由哈希ID提交的提交,则子模块存储库的hash
会更改。它要么成为分支名称的附件,要么指向另一个提交,仍处于分离HEAD模式。
这时,子模块和超级项目不同步。超级项目Git对此不做任何事情。您可以控制,选择所需的提交。您甚至可以进行新的提交并将它们git checkout
提交到上游。完成所需的所有提交和HEAD
处理并正确安排所有内容后,您应该爬出子模块工作树,回到超级项目中。
默认情况下,现在git push
和git checkout
(这里也有很多控制旋钮)告诉您,超级项目正在调用一些哈希 H ,但是该子模块还有其他一些哈希 S 签出。 (如果设置了控制旋钮,它们可能也可能不会告诉您子模块本身是否需要提交。)如果希望下一个超级项目提交记录在此子模块的gitlink中,则此新的提交哈希< em> S ,您运行:
git status
(或git diff
应该做同样的事情,这就是令人困惑的原因)。这将更新索引中的gitlink以记录哈希ID S 而不是 H ,这样,下一个超级项目提交将在git add path-to-submodule
命令上告诉子模块Git:签出提交S,作为独立的HEAD 。
一旦超级项目中的索引与实际检出的子模块中的git add -A
相匹配,该子模块就不会列在未上演提交的更改中部分。如果索引中gitlink中的哈希与git submodule update
中gitlink中的哈希不匹配,则HEAD
将列出要提交的更改中子模块的路径< / em>。
答案 1 :(得分:2)
,因此当我向父母询问其身份时,没有提及它的未登台状态吗?
除非您使用Git 1.7.2 or more,否则它将仍然报告子模块中的更改:
--ignore-submodules[=<when>]
选项:
git status --ignore-submodules=dirty
配置status.submoduleSummary
您可以看到original discussion (back in 2010, for Git 1.7.x) here,它通向该功能:
顺便说一句,我认为行动路线将使生成的git在内部保持一致,因为默认情况下,所有内容都将其工作树中具有未跟踪路径的子模块报告为肮脏。
在“ git status”输出的“ Untracked”部分中,我们在超级项目中列出了一条未跟踪的路径(即运行“
git status
”的路径),以提醒用户该路径可能是一个忘记添加的新文件(除非被忽略)。
但这不会使工作树变脏。当子模块中有未跟踪的路径时:
- 在超级项目级别的
该子模块在“已更改但未更新”部分中列出。
即使子模块的工作树不是 ,这也会使超级项目的工作树变脏。“
git diff
”输出表明子模块已修改(即,显示了“ -dirty”),但是在子模块中运行时,未显示任何更改。我认为这在UI级别是错误的设计;报告未跟踪的 作为提醒用户的潜在错误的不容忽视的途径是一件好事, 但是目前的“
status
”和“diff
”这样做没有多大意义 给我。