【问题标题】:Git command line - know if in submodule?Git命令行 - 知道是否在子模块中?
【发布时间】:2011-09-09 08:50:14
【问题描述】:

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

我猜你可以使用git rev-parse --show-toplevel 找到 repo 根目录,然后 cd-ing 上一层,再次找到该 repo 的根目录,然后将子模块列表与当前目录进行比较,但这似乎很棘手...

【问题讨论】:

  • 对于任何找到这个的人,这是我在andrewray.me/bash-prompt-builder/index.html中使用的项目
  • git rev-parse --git-dir | grep '\.git/modules' 怎么样?或者如果您只需要 git 目录,则只需 git rev-parse --git-dir
  • 注意:使用 Git 2.13(2017 年第二季度),实际使用的命令是 git rev-parse --show-superproject-working-tree。见我的edited answer below

标签: git bash command-prompt git-submodules


【解决方案1】:

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

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

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

参见Stefan Beller (stefanbeller)commit bf0231c(2017 年 3 月 8 日)。
(由 Junio C Hamano -- gitster -- 合并于 commit 3edcc04,2017 年 3 月 17 日)

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 文件引用了实际子模块 git repo 的路径,存储在 parent repo .git/modules 子文件夹中。


(原答案:2011 年 9 月)

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

一个肮脏的伎俩是:

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

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

【讨论】:

  • 还是真的吗?至少在 git 2.1.2 中,子模块包含一个简单的“.git”文件,上面写着“gitdir: relative/path/to/parent/.git/modules/path/to/submodule/”。
  • @QuentinPradet 是的。我已将您的评论包含在答案中以提高知名度。 .git file 应该意味着 repo 是一个子模块。
  • 获取超级项目路径,无论子模块的内部/外部:git rev-parse --show-superproject-working-tree --show-toplevel |头 -1
  • @JethroYu 谢谢。我已将您的链接包含在答案中以提高知名度。
【解决方案2】:

下面是一个 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 回来(所以它只会在第一个子模块 是匹配)。我的版本检查而不更改目录;这可以通过 cd-ing 在子 shell 中完成,但返回退出代码会变得复杂

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

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

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

  • 我将_git_dir 重命名为top_level(这样更容易混淆,因为GIT_DIR 有其他含义)

剩余问题:

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

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

  • 我还建议您捕获错误(使用 'set -e'、'trap "return 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

【讨论】:

  • 如果您只是在回购中签出回购,这会返回误报吗?
  • @Andy:是的。所以你可以把名字改成 is_nested_worktree
  • 我修改了消除误报的功能,您有什么建议吗? gist.github.com/1208078
  • @Andy:我提出了一个基于你的改进脚本(另见gist.github.com/1208393
  • 我认为您对 cd 错误有误,cd "$parent_git/$line" 将是完整路径,而不是相对路径。
【解决方案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目录

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

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

【讨论】:

  • 有趣的是,这似乎不适用于嵌套子模块。
  • @KeithSmiley 我认为它也适用于嵌套子模块。至少在当前最新版本 2.9.3 中。如果您在子模块中通过git submodule add... 而不是git clone ... 创建子模块。
  • 这似乎是最有效的方法;本质上你只需要is_submodule() { ! [[ "$(git rev-parse --git-dir 2&gt;/dev/null)" =~ \.git$ ]]; }
  • 一点更新:从顶层目录运行检查:alias issub='( cd $(git rev-parse --show-toplevel) &amp;&amp; test $(git rev-parse --git-dir) != ".git"; )'
【解决方案4】:

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

然后在父模块中显示子模块路径也很好 - 我打算使用它来显示 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

【讨论】:

    【解决方案5】:

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

    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"
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-06
      • 2017-05-03
      • 2016-10-14
      • 2020-08-16
      • 1970-01-01
      • 1970-01-01
      • 2014-08-19
      • 2021-02-01
      • 2013-12-05
      相关资源
      最近更新 更多