在了解git submodule summary
的确切用途时,我遇到了一些问题?我们如何以及何时使用此命令?我也无法理解--files
选项的重要性。对我来说,不使用标签似乎与使用标签相同。
此外,它与git submodule status
有何不同?我非常困惑。如果有帮助,我一直在阅读命令的Documentation。
非常感谢您的帮助! :)
答案 0 :(得分:2)
对于git submodule status
:
$ git submodule status
hash-1 path-1 (describe-output-1)
hash-2 path-2 (describe-output-2)
:
hash-n path-n (describe-output-n)
对于每个子模块路径,它告诉您在该子模块路径中检出的提交的哈希ID,以及在该子模块中运行git describe
的结果。例如,如果您看到
51ebf55b9309824346a6589c9f3b130c6f371b8f foo (v2.25.0-462-g51ebf55b93)
作为输出,但随后在git checkout v2.15.0
目录中做了一个foo
:
(cd foo; git checkout v2.15.0)
然后再次运行它,您会看到:
+cb5918aa0d50f50e83787f65c2ddc3dcb10159fe foo (v2.15.0)
相反。 (+
符号表明它不同步;请参见下文。)
哈希ID只是在每个子模块中运行git rev-parse HEAD
的结果。 describe输出只是在每个子模块中运行git describe
的结果。中间的路径是您需要提供给cd
(更改目录)命令以从超级项目切换到给定子模块的参数。
对于git submodule summary
,细节要复杂一些。不过,这基本上在每个子模块中运行git log
。
请记住,一个子模块只不过是另一个Git存储库(一个Git称为子模块的子模块),以及此 Git存储库中的一些胶水, Git称之为 superproject 。超级项目中的“胶水”由极少量的项目组成:
git clone
子模块所需的信息,该信息存储在名为.gitmodules
的文件中。仅当您首先告诉超级项目Git进行克隆时(例如,通过git submodule update --init
才能使用此方法。
子模块的路径名,在超级项目中显示。超级项目Git将创建一个空目录/文件夹(无论您喜欢使用哪个术语)来保存此子模块的工作树。 1
提交哈希ID 。超级项目Git将使用此提交哈希ID,实际上,运行(cd path; git checkout hash)
将子模块Git置于分离的HEAD 模式,并检查该特定提交。
最后两个项目存储在您在超级项目中进行的每个新提交中(并且已经存储在现有提交中)。 2 为了获取存储,路径名和提交哈希ID必须存储在Git的 index 中,因为Git从索引中进行所有新提交。
(如果您不清楚Git的 index 与您的工作树之间的区别,请参阅What's the difference between HEAD, working tree and index, in Git?和What does git-rm mean by working tree and index?。)
1 在现代Git中,出现在该路径中的子模块的.git
是一个普通文件,其内容将是子模块Git可以在其中找到存储库的路径。超级项目Git会将存储库数据库移出子模块。 Git将此称为吸收子模块。在旧版Git中,子模块将具有自己的.git
目录/文件夹,其中包含子模块Git存储库数据库。
2 实际上,第一项.gitmodules
文件也应该包含在所有这些提交中,但是由于它是普通文件,因此没有什么特别的:像处理任何普通文件一样使用它。由于超级项目只真正需要一次,因此在克隆子模块时,如果您无意或有意将其排除在新的提交之外,直到其他人尝试使用该提交作为开始时,您才会注意到指向超级项目的新克隆。
由于更改一个.gitmodules
文件非常少,并且它像其他文件一样携带提交,因此这几乎不是问题。仅当您首先使用git submodule add
以外的内容创建子模块时,这才是主要问题。
同时记录路径和哈希ID并准备进行下一次提交的超级项目实体称为 gitlink 。它仅存在于Git的索引中,因此很难看到。 (您可以使用git ls-files --stage
转储索引内容,但这通常太冗长了。)但是它总是存在的:它说要使用 this 提交,请按一个独立的HEAD, this 子模块中的 this 哈希ID。
让我们假设路径sub
(在索引中,为:sub
或:0:sub
处有一个子模块,这里的编号是暂存槽)。在超级项目中进行提交时,此gitlink进入提交。您可以从索引中读取它:
git rev-parse :sub
或从当前提交中读取它:
git rev-parse HEAD:sub
或从任何提交中读取它:
git rev-parse <hash>:sub
从给定的提交哈希ID中获取sub
的存储的gitlink哈希ID。
如果您在超级项目中运行git submodule update
,则Git将根据当前索引中的任何哈希ID来执行适当的(cd sub; git checkout <hash>)
。如果子模块存储库“干净”,那么git checkout
将干净地签出该特定的提交。
但是每个子模块都是一个Git存储库-工作树,索引和基础存储库数据库。 您可以随意使用cd sub
和git checkout
,也可以弄脏 (sub
的)索引和/或其工作-树。而且,该子模块可以有自己的分支名称-这是一个Git存储库,每个Git存储库都有分支名称,对吗?例如,假设您cd sub; git checkout master
。现在,该子模块位于分支上的 中,而不处于分离式HEAD 模式下。您可以进行新的提交,运行git merge
和/或运行所有其他命令。您可以从某个上游存储库中获取新的提交。您可以做任何您想做的事情:这是一个Git存储库,其中提供了所有Git命令。
那么,假设您已经对充当某些超级项目的子模块的某些Git存储库做了什么—并不重要。现在,您回到超级项目(cd ..
),然后在超级项目中 ,您询问:您建议检出哪个提交?从超级项目的索引或提交中读取超级项目中的 gitlink 条目。
您有两个哈希ID。他们可能是一样的!也许子模块中的master
是存储在超级项目的gitlink中的哈希ID。或者,也许他们不同。如果您刚才在子模块中进行了新的提交,则它们肯定是不同的,因为每个新的提交哈希ID都是唯一的。
如果两者不同,git submodule status
将打印+<hash>
;它打印的哈希是在sub
中实际检出的哈希。如果两者相同,则将打印(单个)哈希ID,而不包含+
。
同时,如果您运行git submodule summary
,则您的超级项目Git:
git log
来查找哪些提交位于这两个哈希ID之间。具体来说,它使用git log --oneline --left-right <hash1>...<hash2>
(请注意--oneline
和此处的三个点;它还会强制使用更多选项,但这些是关键选项)。 hash1
值是 recommended 哈希值,而 hash2
值是实际签出的值哈希。该列表的结果是显示可以从 hash1
而不是 hash2
(以<
前缀)访问的提交和提交可以从 {hash2
访问,但不能从 hash1
(以>
开头)访问。
(有关可达性的更多信息,请参见Think Like (a) Git。)
git submodule summary
:--files
与--cached
我也无法理解
--files
选项的重要性
--files
选项是默认选项。 --cached
选项更改了git submodule summary
获取其两个哈希ID的位置。与其从索引(:sub
)中获取第一个哈希,然后进入子模块并读取第二个HEAD
值,它从当前提交< / em>(HEAD:sub
)并从索引(:sub
中获取 second 。其其余操作相同:进入子模块并使用适当的选项运行git log
。