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

发布于 2024-12-03 17:43:30 字数 231 浏览 0 评论 0原文

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

我想你可以使用 git rev-parse --show-toplevel 找到存储库根目录,然后 cd-ing 上一个级别,再次找到该存储库的根目录,然后比较子模块列表到当前目录,但这看起来很粘......

Is there any way in git to know if you're in a submodule? You can do thinks like git submodule foreach in the parent directory but I can't seem to come up with a generic way to show that you're in a submodule if you're in one, or in any of the child directories inside the submodule.

I guess you could find the repo root with git rev-parse --show-toplevel, and then cd-ing up a level, and finding the root of that repo again and then comparing the list of submodules to the current directory, but that seems so sticky...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

岁月打碎记忆 2024-12-10 17:43:30

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

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

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

请参阅 提交bf0231c(2017 年 3 月 8 日),作者:Stefan Beller (stefanbeller)。< br>
(由 Junio C Hamano -- gitster -- 合并于 提交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 | git rev-parse --show-superproject-working-tree --show-toplevel |头-1

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

jeffrson 添加了 评论(2023):

现有的“.git”本身是不够的,因为这对于工作树来说是相同的。
但是,该文件应分别包含字符串“modules”或“worktrees”作为目标的一部分。


(原始答案:2011 年 9 月)

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

一个肮脏的伎俩是:

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

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

(Update April 2017 for Git 2.13, Q2 2017)

There is now an official command to determine if a repo is a submodule of a parent repo:

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

See commit bf0231c (08 Mar 2017) by Stefan Beller (stefanbeller).
(Merged by Junio C Hamano -- gitster -- in commit 3edcc04, 17 Mar 2017)

rev-parse: add --show-superproject-working-tree

In some situations it is useful to know if the given repository
is a submodule of another repository.

Add the flag --show-superproject-working-tree to git-rev-parse to make it easy to find out if there is a superproject.
When no superproject exists, the output will be empty.

Jethro Yu suggests in the comments:

get super project path regardless inside/outside of submodule:

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

(Update 2014) As noted by Quentin Pradet, more recent Git submodule repos show a simple .git file instead of a .git folder.
That .git file reference the path of the actual submodule git repo, stored in the parent repo .git/modules subfolder.

jeffrson adds in the comments (2023):

Existing '.git' itself is not sufficient, because that's the same for worktrees.
However, the file should contain the string "modules" or "worktrees", respectively, as part of the target.


(Original answer: Sept. 2011)

The very nature of a submodule is for the git repo acting as submodule has no idea it is used as a submodule by a parent repo.

One dirty trick would be to:

  • change a file
  • go back one level above the current repo
  • try a "git status --ignore-submodules=none"
  • restore the changed file.

If you see the file in the result of the git status, your repo should be a submodule.
If it is only a nested repo, the git status should ignore your nested repo entirely.

删除会话 2024-12-10 17:43:30

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

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

编辑 响应您建议的脚本:

看起来不错。

  • 中存在错误

    用于 $submodules 中的行;执行 cd "$parent_git/$line"; \
        如果 [[ `pwd` = $_git_dir ]];然后返回0;菲; \
    完毕
    


,因为它不会 cd 返回(所以只有在第一个子模块
是匹配的)。我的版本检查无需更改目录;这可以通过在子 shell 中执行 cd 来完成,但是返回退出代码会变得很复杂

  • 我不知道你从哪里得到 $_git_dir< /code> 来自 - 我使用 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

Here is a shell function that you can use to detect this:

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

Edit In response to your proposed script:

Looking good.

  • There is a bug in

    for line in $submodules; do cd "$parent_git/$line"; \
        if [[ `pwd` = $_git_dir ]]; then return 0; fi; \
    done
    

because it won't cd back (so it would only work if the first submodule
is a match).
My version checks without changing directories; That could be done done by cd-ing in a subshell, but returning the exitcode is getting complicated that way

  • I don't know where you get $_git_dir from - I used basename(1) to get that
    information (see below).

  • There was also a problem with submodules containing a space in the name. In my version, there is still a problem with newlines in submodule names left, but I don't care enough to fix that. (Note the 'idiomatic' way to avoid having the while read in a subshell without needing new bash-isms like readarray)

  • finally declaring all the vars local fixes potential problems when using this
    inside other scripts (e.g. when the outer script uses the $path variable...)

  • I renamed _git_dir to top_level (which is less confusing, because GIT_DIR means something else)

Remaining issues:

  • I don't know whether git supports it (I don't think so) but this script could fail if the submodule directory is a symlink (because "$top_level/.." might resolve outside the containing repository)

  • submodule names with newlines will not be recognized properly

  • I also suggest you trap errors (either with 'set -e', 'trap "return 1"
    ERR' or similar) -- not in my script/exercise for reader

#!/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
}

Usage

if is_submodule; then
    echo "In a submodule!"
else
    echo "Not in a submodule"
fi
蓬勃野心 2024-12-10 17:43:30

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

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

除非您设置 $GIT_DIR< /code> 这将是这种情况下的返回值(请参阅 rev-parse ):

--git-dir

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

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

try git rev-parse --git-dir which will return ".git" if and only if called from the project root:

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

unless you set $GIT_DIR which will be the returned value in that case (see rev-parse):

--git-dir

Show $GIT_DIR if defined. Otherwise show the path to the .git directory. The path shown, when relative, is relative to the current working directory.

If $GIT_DIR is not defined and the current directory is not detected to lie in a Git repository or work tree print a message to stderr and exit with nonzero status.

请恋爱 2024-12-10 17:43:30

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

然后显示父模块内的子模块路径也很好 - 我计划使用它来显示 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

I tried the script suggested above and it didn't work for me. Of course, I may be the only person in the world who has a submodule that's not a direct child of the parent module. The code above assumes that it is.

It would also be nice to then show the submodule path inside the parent - I plan to use this to show a bash shell prompt telling me if I'm in a submodule, and where.

Here's my update:

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
-小熊_ 2024-12-10 17:43:30

所选答案不适用于不在顶层的子模块。这确实并且也更简单:

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

The selected answer doesn't work for submodules that aren't at the top level. This does and is also simpler:

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"
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文