Простой способ получить последние из всех подмодулей git

Мы используем подмодули git для управления парой крупных проектов, которые зависят от многих других библиотек, которые мы разработали. Каждая библиотека представляет собой отдельный репозиторий, внесенный в зависимый проект в виде подмодуля. Во время разработки мы часто хотим просто взять последнюю версию каждого зависимого подмодуля.

Есть ли в git встроенная команда для этого? Если нет, то как насчет пакетного файла Windows или аналогичного, который может это сделать?

24 ответа

Решение

Для git 1.8.2 или выше опция --remote добавлена ​​поддержка обновления до последних подсказок удаленных веток:

git submodule update --recursive --remote

Это имеет дополнительное преимущество, заключающееся в уважении любых веток "не по умолчанию", указанных в .gitmodules или же .git/config файлы (если они у вас есть, по умолчанию это origin / master, в этом случае некоторые другие ответы здесь также будут работать).

Для git 1.7.3 или выше вы можете использовать (но ниже приведены ошибки, касающиеся того, какое обновление все еще применяется):

git submodule update --recursive

или же:

git pull --recurse-submodules

если вы хотите вытащить свои подмодули к последним коммитам, на что указывает репо.

Примечание: если вы впервые оформляете репо, вам нужно использовать --init первый:

git submodule update --init --recursive

Для более старых версий git 1.6.1 или выше вы можете использовать что-то похожее (модифицированное для соответствия):

git submodule foreach git pull origin master

Смотрите git-submodule(1) для подробностей

Если вам нужно вытащить материал для субмодулей в свои репозитории субмодулей, используйте

git pull --recurse-submodules

особенность git, впервые изученная в 1.7.3.

Но это не будет проверять правильные коммиты (те, на которые указывает ваш главный репозиторий) в подмодулях

Для проверки правильности коммитов в ваших подмодулях вы должны обновить их после использования

git submodule update --recursive --remote

На init запускается следующая команда:

git submodule update --init --recursive

из каталога git repo лучше всего работает для меня.

Это будет тянуть все последние, включая подмодули.

Разъяснения

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            --init without the explicit init step if you do not intend to customize
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

После этого вы можете просто запустить:

git submodule update --recursive

из каталога git repo лучше всего работает для меня.

Это будет тянуть все последние, включая подмодули.

Разъяснения

git - the base command to perform any git command
    submodule - Inspects, updates and manages submodules.
        update - Update the registered submodules to match what the superproject
        expects by cloning missing submodules and updating the working tree of the
        submodules. The "updating" can be done in several ways depending on command
        line options and the value of submodule.<name>.update configuration variable.
            any submodule locations.
            --recursive is specified, this command will recurse into the registered
            submodules, and update any nested submodules within.

Примечание: это с 2009 года и, возможно, тогда было хорошо, но сейчас есть лучшие варианты.

Мы используем это. Это называется git-pup:

#!/bin/bash
# Exists to fully update the git repo that you are sitting in...

git pull && git submodule init && git submodule update && git submodule status

Просто поместите его в подходящий каталог bin (/usr/local/bin). Если в Windows вам может понадобиться изменить синтаксис, чтобы заставить его работать:)

Обновить:

В ответ на комментарий оригинального автора о включении всех заголовков всех подмодулей - это хороший вопрос.

Я уверен, что git не имеет команды для этого внутри. Для этого вам необходимо определить, что на самом деле является HEAD для подмодуля. Это может быть так просто, как сказать master самая актуальная ветка и т.д...

После этого создайте простой скрипт, который выполняет следующие действия:

  1. проверять git submodule status для "модифицированных" репозиториев. Первый символ выходных строк указывает на это. Если суб-репо изменен, вы НЕ МОЖЕТЕ продолжить.
  2. для каждого репо в списке, перейдите в его каталог и запустите git checkout master && git pull, Проверьте на ошибки.
  3. В конце я предлагаю вам распечатать дисплей для отображения текущего статуса подмодулей - возможно, предложить им добавить все и зафиксировать?

Я хотел бы отметить, что этот стиль не совсем то, для чего были созданы подмодули git. Как правило, вы хотите сказать, что "LibraryX" имеет версию "2.32" и будет оставаться такой, пока я не скажу "обновить".

Это в некотором смысле то, что вы делаете с описанным сценарием, но просто более автоматически. Требуется осторожность!

Обновление 2:

Если вы работаете на платформе Windows, вы можете захотеть использовать Python для реализации скрипта, так как он очень эффективен в этих областях. Если вы используете unix/linux, то я предлагаю всего лишь скрипт bash.

Нужны какие-либо разъяснения? Просто оставьте комментарий.

Хенрик на правильном пути. Команда 'foreach' может выполнить любой произвольный скрипт оболочки. Два варианта, чтобы вытащить самый последний может быть,

git submodule foreach git pull origin master

а также,

git submodule foreach /path/to/some/cool/script.sh

Это будет перебирать все инициализированные подмодули и запускать заданные команды.

У меня на Windows работает следующее.

git submodule init
git submodule update

Для меня git 2.24.03, обновитесь до последней фиксации удаленных веток, определенных в .gitmoodule.

git submodule update --recursive --init

git версии 2.24.3 (Apple Git-128)

Обратите внимание: кто-то сказал, что это то же самое, что и git submodule update --recursive --remote. Но из моего теста git pull --recurse-submodules может не обновляться до последней фиксации удаленных веток, определенных в .gitmoodule.

Первый раз

Подмодуль Clone и Init

git clone git@github.com:speedovation/kiwi-resources.git resources
git submodule init

Остальное

Во время разработки просто потяните и обновите субмодуль

git pull --recurse-submodules  && git submodule update --recursive

Обновите подмодуль Git до последней фиксации на источнике

git submodule foreach git pull origin master

Предпочтительный способ должен быть ниже

git submodule update --remote --merge

примечание: последние две команды имеют одинаковое поведение

Редактировать:

В комментариях было указано (автором philfreo), что требуется последняя версия. Если есть вложенные подмодули, которые должны быть в их последней версии:

git submodule foreach --recursive git pull

----- устаревший комментарий ниже -----

Разве это не официальный способ сделать это?

git submodule update --init

Я использую это каждый раз. Пока проблем нет.

Редактировать:

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

git submodule foreach --recursive git submodule update --init 

Который также будет рекурсивно тянуть все подмодули, то есть зависимости.

Может случиться так, что ветка по умолчанию ваших подмодулей не masterВот как я полностью автоматизирую обновления подмодулей Git:

git submodule init
git submodule update
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'

Я не знаю, с какой версии git это работает, но вот что вы ищете:

git submodule update --recursive

Я использую это с git pull обновить корневой репозиторий тоже:

git pull && git submodule update --recursive

Приведенные выше ответы хороши, однако мы использовали git-hooks, чтобы сделать это проще, но получается, что в git 2.14 вы можете установить git config submodule.recurse Значение true, чтобы включить подмодули, чтобы они обновлялись при загрузке в ваш репозиторий git.

Это будет иметь побочный эффект, когда вы будете подталкивать все подмодули, которые у вас есть, если они находятся на ветках, но если вам уже нужно такое поведение, это может помочь.

Чтобы прояснить некоторые вещи, основываясь на уже доступных ответах на получение « последнего » кода каждого подмодуля с пульта дистанционного управления.

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

      git submodule update --recursive
  - or -
git pull --recurse-submodules --jobs=X

Если " последний " означает последний из основных , то может сработать что-то вроде этого:

      git submodule foreach "git checkout main && git pull"

К сожалению, это означает, что нет опции «--jobs», поэтому мы не можем запускать ее параллельно. Самое близкое к параллельному запуску, которое я видел, - использование Python кодаpfs .

Я часто использую эту команду, пока работает.

git pull
git submodule foreach --recursive git checkout master
git submodule foreach --recursive git pull

Надеюсь, это быстрее.

Как отмечено в антитоксика user339872 простой ответеgit submodule foreach --recursive git pullможет быть достаточно.

Примечания к ответу user5097539git pull --recurse-submodulesможет отличаться.

Вы можете проверить и посмотреть, что происходит с подробным параметром:

      git pull -v --recurse-submodules

Но для этого вам понадобится Git 2.40 (1 квартал 2023 г.).

" " ( ) попытался перейти к основному ( ), который не понял запроса и вырвался: это было исправлено в Git 2.40 (1 квартал 2023 г.).

См. (10 декабря 2022 г.) Свена Стрикрота ( csware) .
(Объединено Junio ​​C Hamano -- gitster-- в коммите b3b9e5c , 28 декабря 2022 г.)

коммит 6f65f84submodule: принять команду обновления

Подписал: Свен Стрикрот

Начиная с a56771a ("builtin/pull: учитывать настройки детализации в подмодулях», 25 января 2018 г., Git v2.17.0-rc0 — слияние указано в пакете № 3 ), « git pull -v --recurse-submodules" ( мужчинаman ) распространяет команду на субмодуль, но поскольку последняя команда не понимает эту опцию, она вылетает.

Учат " git submodule update" ( manмужчина ), чтобы принять возможность исправить это.

Нет больше "рвоты" (т.е. отображения использования 'git submodule foreach [--quiet] [--recursive] [--] <command>') поскольку-vбыл неизвестным вариантом дляgit submodule.

Git для Windows 2.6.3:

git submodule update --rebase --remote

Посмотрите на http://lists.zerezo.com/git/msg674976.html который вводит параметр --track

С верхнего уровня в репо: подмодуль git foreach git checkout разработать подмодуль git foreach git pull

Это переключит все ветки на разработку и загрузку последних

Все, что вам нужно сделать сейчас, это просто git checkout

Просто убедитесь, что он включен через этот глобальный конфиг: git config --global submodule.recurse true

Я сделал это, адаптировав gahooa выше:

Интегрировать это с мерзавцем [alias]...

Если ваш родительский проект имеет нечто подобное в .gitmodules:

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = git@github.com:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = git@github.com:jkaving/intellij-colors-solarized.git

Добавьте что-то подобное в ваш.gitconfig

[alias]
    updatesubs = "!sh -c \"git submodule init && git submodule update && git submodule status\" "

Затем, чтобы обновить ваши подмодули, запустите:

git updatesubs

У меня есть пример этого в моем репозитории установки среды.

Вот командная строка для извлечения из всех ваших репозиториев git, являются ли они подмодулями или нет:

ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
find "$ROOT" -name .git -type d -execdir git pull -v ';'

Если вы используете его в своем верхнем git-репозитории, вы можете заменить "$ROOT" в .,

Я работал над этим простым скриптом оболочки, который отлично работает для меня.

      #!/bin/bash

#git init
git init

#git clone repo including submodules
git clone --recurse-submodules https://github.com/username/project.git

#change directory -repo
cd project

#update the remote ie tag/commits
git submodule update --remote

#add commit 
git commit -a -m "commit in submodule"

#git push 
git push -u origin 

Замечание: не слишком легкий способ, но работоспособный и у него есть свои уникальные плюсы.

Если кто-то хочет клонировать только HEAD ревизия репозитория и только HEADИз всех его подмодулей (т. е. для извлечения "ствола") можно использовать следующий скрипт Lua. Иногда простая команда git submodule update --init --recursive --remote --no-fetch --depth=1 может привести к невосстановимому git ошибка. В этом случае нужно очистить подкаталог .git/modules подмодуль каталогов и клонов вручную, используя git clone --separate-git-dir команда. Единственная сложность состоит в том, чтобы узнать URL, путь .git каталог подмодуля и путь подмодуля в дереве суперпроекта.

Примечание: скрипт проверяется только на https://github.com/boostorg/boost.git репозиторий. Его особенности: все субмодули размещены на одном хосте и .gitmodules содержит только относительные URL-адреса.

-- mkdir boost ; cd boost ; lua ../git-submodules-clone-HEAD.lua https://github.com/boostorg/boost.git .
local module_url = arg[1] or 'https://github.com/boostorg/boost.git'
local module = arg[2] or module_url:match('.+/([_%d%a]+)%.git')
local branch = arg[3] or 'master'
function execute(command)
    print('# ' .. command)
    return os.execute(command)
end
-- execute('rm -rf ' .. module)
if not execute('git clone --single-branch --branch master --depth=1 ' .. module_url .. ' ' .. module) then
    io.stderr:write('can\'t clone repository from ' .. module_url .. ' to ' .. module .. '\n')
    return 1
end
-- cd $module ; git submodule update --init --recursive --remote --no-fetch --depth=1
execute('mkdir -p ' .. module .. '/.git/modules')
assert(io.input(module .. '/.gitmodules'))
local lines = {}
for line in io.lines() do
    table.insert(lines, line)
end
local submodule
local path
local submodule_url
for _, line in ipairs(lines) do
    local submodule_ = line:match('^%[submodule %"([_%d%a]-)%"%]$')
    if submodule_ then
        submodule = submodule_
        path = nil
        submodule_url = nil
    else
        local path_ = line:match('^%s*path = (.+)$')
        if path_ then
            path = path_
        else
            submodule_url = line:match('^%s*url = (.+)$')
        end
        if submodule and path and submodule_url then
            -- execute('rm -rf ' .. path)
            local git_dir = module .. '/.git/modules/' .. path:match('^.-/(.+)$')
            -- execute('rm -rf ' .. git_dir)
            execute('mkdir -p $(dirname "' .. git_dir .. '")')
            if not execute('git clone --depth=1 --single-branch --branch=' .. branch .. ' --separate-git-dir ' .. git_dir .. ' ' .. module_url .. '/' .. submodule_url .. ' ' .. module .. '/' .. path) then
                io.stderr:write('can\'t clone submodule ' .. submodule .. '\n')
                return 1
            end
            path = nil
            submodule_url = nil
        end
    end
end

Я думаю, вам придется написать сценарий для этого. Честно говоря, я мог бы установить Python, чтобы вы могли использовать os.walk в cd для каждого каталога и введите соответствующие команды. Использование python или другого скриптового языка, отличного от пакетного, позволит вам легко добавлять / удалять подпроекты без необходимости изменять скрипт.

Другие вопросы по тегам