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

时间:2011-09-09 08:50:14

标签: git bash command-prompt git-submodules

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

我猜你可以找到带有git rev-parse --show-toplevel的repo root,然后再升级一个级别,然后再次查找该repo的根目录,然后将子模块列表与当前目录进行比较,但似乎这么粘......

5 个答案:

答案 0 :(得分:20)

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

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

cd /path/to/potential/submodule/repo
git rev-parse --show-superproject-working-tree

commit bf0231cStefan Beller (stefanbeller)(2017年3月8日) Junio C Hamano -- gitster --于2017年3月17日commit 3edcc04合并)

  

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

     

在某些情况下,知道给定的存储库是否有用   是另一个存储库的子模块。

     

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

Jethro Yu建议in the comments

  

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

git rev-parse --show-superproject-working-tree --show-toplevel | head -1

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


(原始答案:2011年9月)

子模块的本质是用于作为子模块的git repo,它不知道它被父级仓库用作子模块。

一个肮脏的伎俩是:

  • 更改文件
  • 返回当前仓库以上一级
  • 尝试“git status --ignore-submodules=none
  • 恢复已更改的文件。

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

答案 1 :(得分:9)

这是一个shell函数,可用于检测:

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

修改以回应您提议的脚本:

看起来不错。

  • 中存在错误
    for line in $submodules; do cd "$parent_git/$line"; \
        if [[ `pwd` = $_git_dir ]]; then return 0; fi; \
    done
    
  • <击>
<击>

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

  • 我不知道你从哪里得到$_git_dir - 我用basename(1)来得到它 信息(见下文)。

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

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

  • 我将_git_dir重命名为top_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
}

用法

if is_submodule; then
    echo "In a submodule!"
else
    echo "Not in a submodule"
fi

答案 2 :(得分:3)

我尝试了上面建议的脚本,但它对我不起作用。当然,我可能是世界上唯一一个子模块不是父模块的直接子模块的人。上面的代码假定它是。

然后显示父模型中的子模块路径也很好 - 我打算用它来显示一个bash shell提示符,告诉我我是否在子模块中,以及在哪里。

这是我的更新:

function is_submodule() {
    local git_dir parent_git module_name path strip
    # Find the root of this git repo, then check if its parent dir is also a repo
    git_dir="$(git rev-parse --show-toplevel)"
    parent_git="$(cd "$git_dir/.." && git rev-parse --show-toplevel 2> /dev/null)"

    if [[ -n $parent_git ]]; then
        strip=$((${#parent_git} + 1))
        module_name=${git_dir:$strip}
        # List all the submodule paths for the parent repo
        while read path
        do
            if [[ "$path" != "$module_name" ]]; then continue; fi
            if [[ -d "$parent_git/$path" ]]; then
                echo $module_name
                return 0;
            fi
        done < <(cd $parent_git && git submodule --quiet foreach 'echo $path' 2> /dev/null)
    fi
    return 1
}

# Usage
submodule=$(is_submodule)
if [[ $? -eq 0 ]]; then
    echo "In a submodule! $submodule"
else
    echo "Not in a submodule"
fi

答案 3 :(得分:3)

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

if `git rev-parse --git-dir` == ".git"
    // in root directory
else
    // in submodule directory

除非您将$GIT_DIR设置为该情况下的返回值(请参阅rev-parse):

  

- GIT-DIR

     

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

     

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

答案 4 :(得分:1)

所选答案对于不在顶层的子模块不起作用。这样做也更简单:

function is_git_submodule() {
    local module_name 

    module_path="$(git rev-parse --show-toplevel 2> /dev/null)"

    # List all the submodule paths for the parent repo and look for our module's path
    (cd "${module_path}/.." && git submodule --quiet foreach 'echo $toplevel/$path' 2> /dev/null) | \
        grep --quiet --line-regexp --fixed-strings "$module_path"
}