我怎样才能知道我是否在 git 子模块中?

how can I find out if I'm inside a git submodule?

tldr;我怎样才能知道我当前的工作目录在子模块目录中?

如果在子模块内部或外部工作,工作流程会有所不同。我一次又一次地感到困惑,因为我不知道我在一个子模块中。

最好 __git_ps1 会告诉我我在子模块中,但显然它没有这样做的规定。

我想修补 __git_ps1 以显示我在子模块中的事实,但我找不到查询 git 的优雅方式。

理想情况下,我希望有一个像这样的 shell 函数:

function current_working_directory_is_in_a_submodule() {
  if some_magic; then
     echo "( $submodule_name )"
  else
     false
  fi
}

什么是 some_magic

您可以查看 .git 目录。如果它 而不是 实际上是一个目录,你可以很确定你在一个子模块中。至少对于 git 的最新版本,.git 条目实际上是一个类似于以下内容的文件:

gitdir: ../../../.git/modules/path/to/submodule

根据子模块的添加方式,它可能仍然有一个 .git 目录。父存储库中有一个 git submodule absorbgitdirs 命令可以 运行 来解决这个问题;来自 git submodule 手册页:

If a git directory of a submodule is inside the submodule, move the git directory of the submodule into its superprojects $GIT_DIR/modules path and then connect the git directory and its working directory by setting the core.worktree and adding a .git file pointing to the git directory embedded in the superprojects git directory.

A repository that was cloned independently and later added as a submodule or old setups have the submodules git directory inside the submodule instead of embedded into the superprojects git directory.

This command is recursive by default.

...但这仍然是有问题的,因为虽然在子模块的根目录中测试很容易,但在深度嵌套的目录中时就更难了(因为那时你将不得不迭代搜索父目录,直到找到 .git 目录或到达 /).


我上面引用的手册页条目为我们指出了第二个更好的选择:

在子模块中,设置了 core.worktree 值(从子模块的根返回到自身的相对路径)。这意味着您可以 (a) 检查 core.worktree 设置是否具有确定您是否在子模块中的值,以及 (b) 您可以使用 core.worktree 的值来确定子模块姓名。这让我们得到类似的东西:

function current_working_directory_is_in_a_submodule() {
  submodule=$(git config core.worktree)
  if [ "$?" -eq 0 ]; then
     echo "( ${submodule##*/} )"
  else
     false
  fi
}

不知道还有没有其他情况会自动设置core.worktree,不过在我有限的测试中好像是这样。

git rev-parse --show-superproject-working-tree

如果当前存储库未被任何项目用作子模块,则不输出任何内容。

子模块性只是一个关于如何使用 repo 的问题,当前的结帐是否是其他结帐认为应该存在的。

您可以在此处查看工作树是否在另一个认为应该结帐的工作树中:

top=`git rev-parse --show-toplevel 2>&-` || exit
if up=`git -C "$top/.." rev-parse --show-toplevel 2>&-` 
then    echo work tree is at ${top#$up/} in another work tree
        at=`git -C "$up" rev-parse :${top#$up/}` && echo ... which thinks $(git cat-file -t $at) $at should be checked out there
fi