如果子模块使用跟踪分支,那么它是如何在内部实现的

时间:2017-09-01 16:20:51

标签: git

我在子模块上阅读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 

内部如何运作?

据我所知:

  • 跟踪分支在子模块克隆存储库中设置
  • 跟踪分支已添加到.gitmodules

但引用提交的特殊文件会发生什么?它是否仍然保存子模块的提交哈希值?

跟踪分支功能是否仅影响我运行时的行为

git submodule update --remote 

因为它检查子模块跟踪分支并检出新的提交并更新主存储库的索引?

1 个答案:

答案 0 :(得分:1)

背景(可以跳到下一部分)

关于子模块要记住的主要事情是,在子模块加入超级项目时,总会有两个 Gits。

超级项目至少有三条信息。其中两个在.gitmodules

  • 完整路径,例如path/to/ProjectA(如果子模块在某些子目录集中是关闭的)或简单地ProjectA(如果子模块位于顶层);和
  • URL,以便在您克隆超级项目(但不是其子模块)之后,Git可以运行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 mergegit rebasegit 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文档在这里保持清晰的区别似乎并不那么好。)