Git командной строки - знаете, если в подмодуле - PullRequest
18 голосов
/ 09 сентября 2011

Есть ли способ в git узнать, есть ли у вас подмодуль? Вы можете сделать что-то вроде git submodule foreach в родительском каталоге, но я не могу придумать общего способа показать, что вы находитесь в подмодуле, если вы в одном, или в любом из дочерних каталогов внутри подмодуль.

Полагаю, вы могли бы найти корень репо с помощью git rev-parse --show-toplevel, а затем перейти на новый уровень и снова найти корень этого репо, а затем сравнить список подмодулей с текущим каталогом, но это выглядит так липко ...

Ответы [ 5 ]

20 голосов
/ 09 сентября 2011

(Обновление в апреле 2017 года для Git 2.13, второй квартал 2017 года)

Теперь существует официальная команда для определения того, является ли репо подмодулем родительского репо:

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

См. коммит bf0231c (08 марта 2017 г.) Стефан Беллер (stefanbeller) .
(объединено Junio ​​C Hamano - gitster - in commit 3edcc04 , 17 марта 2017 г.)

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

В некоторых ситуациях полезно знатьесли данный репозиторий является подмодулем другого репозитория.

Добавьте флаг --show-superproject-working-tree в git-rev-parse, чтобы упростить поиск наличия суперпроекта.
Если суперпроекта не существует, выводбудет пустым.

Jethro Yu * ​​1035 * предлагает в комментариях :

получить путь к суперпроекту независимо от того, внутри или снаружисубмодуль:

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

(обновление 2014 г.) Как отмечает Квентин Прадет , более поздние репозитории подмодулей Git показывают простой .git файл инстпапка .git.
Этот файл .git ссылается на путь фактического подмодуля git repo, хранящегося в подпапке parent repo .git/modules.


(Оригинальный ответ: сентябрь 2011 г.)

Сама природа подмодуля заключается в том, что git-репо, действующий как подмодуль, не подозревает, что он используется в качестве подмодуля родительским репо.

OneГрязный трюк заключался бы в том, чтобы:

  • изменить файл
  • вернуться на один уровень выше текущего репо
  • попробовать "git status --ignore-submodules=none"
  • восстановить измененный файл.

Если вы видите файл в результате git status, ваше хранилище должно быть субмодулем.
Если это только вложенное хранилище, git status следует полностью игнорировать ваше вложенное хранилище.

9 голосов
/ 09 сентября 2011

Вот функция оболочки, которую вы можете использовать для обнаружения этого:

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

Редактировать В ответ на предложенный сценарий:

Хорошо выглядит.

  • В * 1013 есть ошибка for line in $submodules; do cd "$parent_git/$line"; \ if [[ `pwd` = $_git_dir ]]; then return 0; fi; \ done

потому что он не вернется на CD (так что он будет работать только если первый субмодуль совпадает). Моя версия проверяет без изменения каталогов; Это можно сделать с помощью cd -ing в подоболочке, но возврат кода выхода усложняется таким образом

  • Я не знаю, откуда вы взяли $_git_dir - я использовал basename (1), чтобы получить это информация (см. ниже).

  • Также была проблема с подмодулями, содержащими пробел в имени. В моей версии все еще есть проблема с символами новой строки в именах подмодулей, но мне все равно, чтобы это исправить. (Обратите внимание на «идиоматический» способ избежать использования while read в подоболочке без необходимости новых интерпретаций типа readarray)

  • наконец, объявление всех локальных переменных исправляет потенциальные проблемы при использовании этого внутри других сценариев (например, когда внешний сценарий использует переменную $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
3 голосов
/ 21 декабря 2014

try 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 и выйдите из него.с ненулевым статусом.

3 голосов
/ 29 марта 2012

Я попробовал сценарий, предложенный выше, и он не работал для меня. Конечно, я могу быть единственным человеком в мире, у которого есть подмодуль, который не является прямым потомком родительского модуля. Код выше предполагает, что это так.

Было бы также неплохо показать путь к субмодулю внутри родителя - я планирую использовать его для отображения приглашения оболочки оболочки bash, сообщающего, нахожусь ли я в подмодуле, и где.

Вот мое обновление:

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
1 голос
/ 09 февраля 2018

Выбранный ответ не работает для подмодулей, которые не находятся на верхнем уровне. Это делает и также проще:

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