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

x6492ojm  于 2023-04-28  发布在  Git
关注(0)|答案(5)|浏览(237)

在git中有没有办法知道你是否在一个子模块中?你可以在父目录中像git submodule foreach这样做,但是我似乎不能想出一个通用的方法来显示你在一个子模块中,如果你在一个子模块中,或者在子模块中的任何子目录中。
我猜你可以用git rev-parse --show-toplevel找到repo的根目录,然后用cd向上一级,再次找到那个repo的根目录,然后将子模块列表与当前目录进行比较,但这看起来太粘了。..

s6fujrry

s6fujrry1#

(2017年4月更新为Git 2。2017年第2季度13日)
现在有一个官方命令来确定一个repo是否是父repo的子模块:

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

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

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

在某些情况下,知道给定的存储库是否是另一个存储库的子模块是有用的。
git-rev-parse中添加标志--show-superproject-working-tree,以便于查找是否存在超级项目。
当不存在超级项目时,输出将为空。
Jethro Yu在评论中建议:
获取超级项目路径,无论子模块内部/外部:

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

(2014年更新)正如Quentin Pradet所指出的,最近的Git子模块存储库显示了一个简单的.git * 文件 *,而不是.git文件夹。
.git文件引用实际子模块git repo的路径,存储在 parent repo .git/modules子文件夹中。
jeffrson添加评论(2023):
现有的'.git'本身是不够的,因为这对于工作树是一样的。
但是,该文件应该分别包含字符串“modules”或“worktrees”作为目标的一部分。
(原文回答:2011年9月)
子模块的本质是作为子模块的git repo不知道它被父repo用作子模块。
一个肮脏的把戏是:

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

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

nuypyhwy

nuypyhwy2#

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

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

编辑回应你的剧本:

看起来不错

  • 有一个bug
for line in $submodules; do cd "$parent_git/$line"; \
    if [[ `pwd` = $_git_dir ]]; then return 0; fi; \
done
  • 因为它不会cd回来(所以它只会在第一个子模块匹配时工作)。**我的版本检查不改变目录;这可以通过在子shell中执行cd-ing来完成,但是这样返回退出码会变得很复杂 *
  • 我不知道你从哪里得到$_git_dir-我使用basename(1)来得到这些信息(见下文)。
  • 还有一个问题是子模块的名称中包含空格。* 在我的版本中,仍然有一个问题,在子模块名称中的换行符,但我不关心足够的修复。(注意避免在子shell中使用while read的“惯用”方法,而不需要像readarray这样的新bash-isms)*
  • 最后声明所有VAR本地修复了在其他脚本中使用时的潜在问题(例如,例如,当外部脚本使用$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
mcvgt66p

mcvgt66p3#

尝试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,并以非零状态退出。

qoefvg9y

qoefvg9y4#

我尝试了上面建议的脚本,它不适合我。当然,我可能是世界上唯一一个拥有不是父模块直接子模块的子模块的人。上面的代码假设它是。
最好显示父模块中的子模块路径--我打算用它来显示一个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
eimct9ow

eimct9ow5#

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

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

相关问题