Git命令行 - 知道是否在子模块中?

And*_*Ray 20 git bash command-prompt git-submodules

有没有办法在git中知道你是否在子模块中?您可以git submodule foreach在父目录中进行思考,但是如果您在子模块中的任何子目录中,或者在子模块内的任何子目录中,我似乎无法想出一个通用的方法来显示您在子模块中.

我想你可以找到repo root git rev-parse --show-toplevel,然后cd一个级别,然后再次查找该repo的根,然后将子模块列表与当前目录进行比较,但这看起来很粘...

Von*_*onC 22

(2017年4月更新为Git 2.13,2017年第2季)

现在有一个官方命令来确定repo是否是父repo的子模块:

cd /path/to/potential/submodule/repo
git rev-parse --show-superproject-working-tree
Run Code Online (Sandbox Code Playgroud)

请参阅Stefan Beller的承诺bf0231c(2017年3月8日)(stefanbeller).
(由Junio C gitsterHamano合并- -提交3edcc04,2017年3月17日)

rev-parse:添加 --show-superproject-working-tree

在某些情况下,了解给定的存储库是否是另一个存储库的子模块很有用.

添加标记--show-superproject-working-tree以便git-rev-parse于查找是否存在超级项目.
如果不存在超级项目,则输出将为空.

Jethro Yu 在评论中建议:

获取超级项目路径,无论子模块内部/外部:

git rev-parse --show-superproject-working-tree --show-toplevel | head -1
Run Code Online (Sandbox Code Playgroud)

(2014年更新)正如Quentin Pradet所指出的,更新的Git子模块repos显示的是一个简单的.git 文件而不是.git文件夹.
.git文件引用存储在 repo .git/modules子文件夹中的实际子模块git repo的路径.


(原答案:2011年9月)

子模块的本质是用于作为子模块的git repo不知道它被父repo用作子模块.

一个肮脏的伎俩是:

  • 更改文件
  • 回到目前的回购价格之上一级
  • 尝试" git status --ignore-submodules=none"
  • 恢复更改的文件.

如果在结果中看到该文件,则git status您的repo应该是子模块.
如果它只是一个嵌套的repo,那么git status应该完全忽略你的嵌套repo.

  • 获取超级项目路径,无论子模块内部/外部: git rev-parse --show-superproject-working-tree --show-toplevel | 头-1 (2认同)

seh*_*ehe 9

这是一个shell函数,您可以使用它来检测:

function is_submodule() 
{       
     (cd "$(git rev-parse --show-toplevel)/.." && 
      git rev-parse --is-inside-work-tree) | grep -q true
}
Run Code Online (Sandbox Code Playgroud)

编辑响应您提议的脚本:

看起来不错.

因为它不会回来(所以它只有在第一个子模块匹配时才有效).我的版本检查而不更改目录; 这可以通过cd在子shell中完成来完成,但是返回exitcode会变得那么复杂

  • 我不知道你从哪里来$_git_dir- 我用basename(1)来获取这些信息(见下文).

  • 子模块在名称中包含空格也存在问题.在我的版本中,子模块名称中的换行仍然存在问题,但我并不在意解决这个问题.(注意'惯用'方法避免while read在子shell中使用而不需要新的bash-isms之类的readarray)

  • 最后声明所有vars本地修复了在其他脚本中使用它时的潜在问题(例如,当外部脚本使用$path变量时...)

  • 我改名_git_dirtop_level(这不太混乱,因为GIT_DIR意味着别的东西)

剩下的问题:

  • 我不知道git是否支持它(我不这么认为)但是如果子模块目录是一个符号链接,这个脚本可能会失败(因为"$ top_level/.."可能在包含的存储库之外解析)

  • 具有换行符的子模块名称将无法正确识别

  • 我还建议您捕获错误(使用'set -e','trap'返回1"ERR"或类似) - 不在我的脚本/练习中为读者

#!/bin/bash

function is_submodule() {
    local top_level parent_git module_name path
    # Find the root of this git repo, then check if its parent dir is also a repo
    top_level="$(git rev-parse --show-toplevel)"
    module_name="$(basename "$top_level")"
    parent_git="$(cd "$top_level/.." && git rev-parse --show-toplevel 2> /dev/null)"
    if [[ -n $parent_git ]]; then
        # List all the submodule paths for the parent repo
        while read path
        do
            if [[ "$path" != "$module_name" ]]; then continue; fi
            if [[ -d "$top_level/../$path" ]];    then return 0; fi
        done < <(cd $parent_git && git submodule --quiet foreach 'echo $path' 2> /dev/null)
        #return 1
    fi
    return 1
}
Run Code Online (Sandbox Code Playgroud)

用法

if is_submodule; then
    echo "In a submodule!"
else
    echo "Not in a submodule"
fi
Run Code Online (Sandbox Code Playgroud)

  • 如果您只是在回购中检查了一个回购,那么这会产生误报吗? (2认同)

ami*_*sim 5

当且仅当从项目根调用时尝试git rev-parse --git-dir才会返回:".git"

if `git rev-parse --git-dir` == ".git"
    // in root directory
else
    // in submodule directory
Run Code Online (Sandbox Code Playgroud)

除非您设置了$GIT_DIR在这种情况下返回的值(请参阅rev-parse):

--git-dir

如果已定义,则显示 $GIT_DIR。否则显示 .git 目录的路径。显示的路径(相对路径)是相对于当前工作目录的。

如果未定义 $GIT_DIR 并且未检测到当前目录位于 Git 存储库或工作树中,则将消息打印到 stderr 并以非零状态退出。