我正在阅读关于子模块的这篇很棒的文章,它解释了子模块作为一种特殊类型的文件保存在主存储库提交树中:
[/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
因为它检查子模块跟踪分支并检查新提交并更新主存储库的索引?
关于子模块要记住的主要事情是在子模块加入超级项目的地方总是涉及两个Git。
超级项目至少有三条信息。两个在.gitmodules
:
path/to/ProjectA
(如果子模块在某些子目录集中)或简单ProjectA
(如果子模块位于顶层);和git clone ...
在您克隆超级项目(但不是其子模块)后,Git 可以运行以获取子模块。该指标(如见过git ls-files --stage
有两条信息:
path/to/projectA
(必须与.gitmodules
条目匹配);和85ab8ba4edf9168ab051ded7ddbbe20861b71528
。由于这些重叠,你显然会失去同步:如果你改变路径,事情就会变得有点奇怪。
不过,子模块本身是一个 Git 存储库。这意味着除了commits之外,它还有 a HEAD
、分支、标签等等。的内容HEAD
代表当前提交。最初,当超级项目控制一切时,子模块的 Git 会被告知:通过按哈希 ID 检出一个特定提交来分离HEAD
,例如,85ab8ba4edf9168ab051ded7ddbbe20861b71528
。
不过,您可以进入子模块,并查看分支名称或不同的标签。您可以运行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...
专门要求提交,但你的子模块没有“开启”那个提交。
现在你的工作是确保超级项目在新的子模块散列就位的情况下正常工作。如果是这样,您可以——在超级项目中——git add
在子模块的路径上运行。这会更新特殊索引条目,保持路径不变,但将新的提交哈希写入其中。
现在您可以git commit
在超级项目中。像往常一样,索引的内容决定了新提交的内容。提交将记录新的哈希 ID。.gitmodules
包含分支名称的内容没有改变,所以.gitmodules
新提交中.gitmodules
记录的版本与旧提交中记录的版本相同。超级项目中新哈希 ID 的唯一标志是存储在提交中的哈希 ID(将被复制回git checkout
超级项目存储库中该提交的索引)是更新后的。
1个在这一点上使用的分支取自.gitmodules
除非有一个submodule.<name>.branch
在设置$GIT_DIR/config
。配置设置会覆盖.gitmodules
设置。这<name>
部分是superproject 中的当前分支名称。所有这些不同的东西都需要限定,因为我们同时查看两个 Git:超级项目 Git 存储库和子模块 Git 存储库。
(现有的 Git 文档似乎不太擅长在这里保持明确的区别。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句