我在子模块上阅读this great article,这解释了子模块在主存储库提交树中保存为一种特殊的文件:
[/tmp/git/super(master)]$ git ls-files --stage
100644 831cdc0dc1b88e69aa9943cf09907ae1bcd031fc 0 .gitmodules
160000 85ab8ba4edf9168ab051ded7ddbbe20861b71528 0 ProjectA <--------
100644 16f5c2d3aa9656fc424352e4cfaa2523c809778b 0 super.txt
其中85ab8ba4edf9168ab051ded7ddbbe20861b71528
是外部/子模块存储库中提交的哈希值。
如果我使用跟踪分支的方法:
# add submodule to track master branch
git submodule add -b master [URL to Git repo];
# update your submodule
git submodule update --remote
内部如何运作?
据我所知:
但引用提交的特殊文件会发生什么?它是否仍然保存子模块的提交哈希值?
跟踪分支功能是否仅影响我运行时的行为
git submodule update --remote
因为它检查子模块跟踪分支并检出新的提交并更新主存储库的索引?
答案 0 :(得分:1)
关于子模块要记住的主要事情是,在子模块加入超级项目时,总会有两个 Gits。
超级项目至少有三条信息。其中两个在.gitmodules
:
path/to/ProjectA
(如果子模块在某些子目录集中是关闭的)或简单地ProjectA
(如果子模块位于顶层);和git clone ...
来获取子模块。 索引(与git ls-files --stage
一样有两条信息:
path/to/projectA
(必须与.gitmodules
条目匹配);和85ab8ba4edf9168ab051ded7ddbbe20861b71528
。由于这些重叠,你显然可能会失去同步:如果你改变路径,事情就会变得有些奇怪。
然而,子模块本身就是一个Git存储库。这意味着除了提交之外,它还有HEAD
,分支,标签等。 HEAD
的内容代表当前提交。最初,当超级项目控制所有内容时,子模块的Git会被告知:通过哈希ID 检出一个特定提交来分离HEAD
,例如85ab8ba4edf9168ab051ded7ddbbe20861b71528
。 / p>
但是,您可以进入子模块,并查看分支名称或其他标记。您可以运行git fetch
以从该子模块Git的 usptream 获取提交,该提交与超级项目无关。简而言之,您可以在任何旧的Git存储库中执行任何操作。
但是一旦你这样做,事情就会失去同步:HEAD
解析的提交ID可能与超级项目中存储的提交ID不匹配。
git submodule add -b master [URL to Git repo];
...跟踪分支已添加到
.gitmodules
是。在那里,等待你的下一个命令:
git submodule update --remote
将它带出那里(或其他地方 1 )并使Git处理子模块运行:
git fetch [potential additional options]
后跟git merge
,git rebase
或git checkout
中的一个,具体取决于更多标记和选项及设置。传递给下一个命令的参数还取决于更多标志,选项和设置。
完成后,子模块本身可能会检查其他一些提交。也就是说,在子模块中运行的git rev-parse HEAD
命名除85ab8ba...
之外的其他内容。所以现在你的超级项目和子项目不同步了:你的超级项目专门要求提交85ab8ba...
,但你的子模块不是&#34; on&#34;提交。
现在,您的工作是确保超级项目能够正确使用新的子模块哈希。如果是这样,您可以在子模块的路径上运行超级项目git add
。这会更新特殊索引条目,保持路径不变,但会在其中写入新的提交哈希。
现在你可以在超级项目中git commit
了。像往常一样,索引的内容决定了新提交的内容。提交将记录新的哈希ID。包含分支名称的.gitmodules
的内容未更改,因此新提交中记录的.gitmodules
版本与旧提交中记录的.gitmodules
版本相同。超级项目中新哈希ID的唯一标志是存储在提交中的哈希ID(将被复制回超级项目存储库中该提交的git checkout
上的索引)是此更新的哈希ID。
1 此时使用的分支取自.gitmodules
,除非<{em>} submodule.<name>.branch
设置$GIT_DIR/config
。配置设置会覆盖.gitmodules
设置。 <name>
部分是超级项目中的当前分支名称 。所有这些不同的东西都需要资格,因为我们同时查看两个Gits:超级项目Git repo和子模块Git repo。
(现有的Git文档在这里保持清晰的区别似乎并不那么好。)