Git子模块在结帐另一个分支时删除

vp_*_*rth 6 git git-submodules

我的 Git 存储库中有几个具有功能的分支。
每个功能都是一些外部存储库,作为子模块插入。
我应该怎么做来纠正分支之间的切换,有和没有子模块?

例子:

$ git init
$ git commit -m "empty" --allow-empty
$ git checkout -b feature
$ git submodule init
$ git submodule add git://feature.git feature
$ git commit -a -m "add feature"
$ git checkout master
warning: unable to rmdir feature: Directory is not empty
Run Code Online (Sandbox Code Playgroud)

我们的master分支工作目录中有一个功能。
如何防止这种情况?

Eri*_*Sun 5

git submodule deinit .
Run Code Online (Sandbox Code Playgroud)

可能会起作用


Von*_*onC 5

使用 Git 2.27(2020 年第 2 季度),情况应该有所改善,并且“ git checkout --recurse-submodules”在嵌套子模块层次结构中效果更好。

请参阅提交 846f34d提交 e84704f提交 16f2b6b提交 8d48dd1提交 d5779b6提交 bd35645(2020 年 2 月 17 日),作者Philippe Blain ( phil-blain)
(由Junio C Hamano 合并 -- gitster--提交 fe87060中,2020 年 3 月 27 日)

unpack-trees:检查是否缺少子模块目录merged_entry

报告人: Philippe Blain
报告人: Damien Robert
签字人: Philippe Blain

使用在没有子模块的分支和具有初始化嵌套子模块的分支之间切换git checkout --recurse-submodules当前会导致致命错误:

$ git checkout --recurse-submodules branch-with-nested-submodules
fatal: exec '--super-prefix=submodule/nested/': cd to 'nested'
       failed: No such file or directory
error: Submodule 'nested' could not be updated.
error: Submodule 'submodule/nested' cannot checkout new HEAD.
error: Submodule 'submodule' could not be updated.
M   submodule
Switched to branch 'branch-with-nested-submodules'
Run Code Online (Sandbox Code Playgroud)

检出成功,但第一级子模块的工作树和索引为

$ cd submodule
$ git -c status.submoduleSummary=1 status
HEAD detached at b3ce885
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
      deleted:    .gitmodules
      deleted:    first.t
      deleted:    nested

fatal: not a git repository: 'nested/.git'
Submodule changes to be committed:

* nested 1e96f59...0000000:

$ git ls-files -s
$ # empty
$ ls -A
.git
Run Code Online (Sandbox Code Playgroud)

签出期间发生致命错误的原因是子 git 进程尝试cd进入尚不存在的嵌套子模块目录。

顺序如下:

  1. 主 git 进程(在超级项目中运行的进程)最终到达write_entry()in entry.c,它创建第一级子模块目录,然后调用submodule_move_head()in ,它在子模块目录中submodule.c生成。git read-tree

  2. 第一个子 git 进程(超级项目子模块中的进程)最终调用check_submodule_move_head()at unpack_trees.c:2021,它submodule_move_head以空运行模式调用,该模式git read-tree在嵌套子模块目录中生成。

  3. 第二个子 git 进程尝试进入atchdir()中尚未存在的嵌套子模块目录,并在执行之前终止。start_command()run-command.c

之所以check_submodule_move_head()在第一个子进程中而不是在主进程中到达,是因为它位于if(submodule_from_ce())构造内部,并submodule_from_ce()返回有效的 struct 子模块指针,而它在主 git 进程中返回空指针。

之所以submodule_from_ce()在主进程中返回空指针,是因为对in 的git调用(从in调用)返回空指针,因为of中的hashmap尚未填充。 它没有被填充,因为在return 和 中,在操作的这个阶段,超级项目的 HEAD 及其索引都不包含任何文件。cache_lookup_path()config_from()submodule_from_path()submodule_from_ce()"for_path"submodule_cachethe_repository
repo_get_oid(repo, GITMODULES_INDEX, &oid)repo_get_oid(repo, GITMODULES_HEAD, &oid)config_from_gitmodules()submodule-config.c-1.gitmodules

相反,在第一个子模块中,哈希映射被填充,因为repo_get_oid(repo, GITMODULES_HEAD, &oid)返回 0 作为第一级子模块的 HEAD,即.git/modules/submodule/HEAD,指向.gitmodules存在的提交并将“嵌套”记录为子模块。

通过在调用之前检查子模块目录是否存在来修复此错误check_submodule_move_head()merged_entry()通过在分支中调用if(!old),即,如果从没有子模块的提交转到存在子模块的提交。

同时保护其他呼叫check_submodule_move_head()即使代码分支在当前错误中没有发挥作用,也以merged_entry(),因为它更安全。else if (!(old->ce_flags & CE_CONFLICTED))

另一个打电话给check_submodule_move_head()对其他函数的unpack_trees.c都已经受到lstat()对程序流程中某处的调用的保护,因此我们不需要对它们进行额外的保护。

当使用该标志调用时,机器中的所有命令unpack_trees都会受到影响,即检出、重置和读取树--recurse-submodules

此错误首先在这里报告