Простой способ получить последние из всех подмодулей 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
самая актуальная ветка и т.д...
После этого создайте простой скрипт, который выполняет следующие действия:
- проверять
git submodule status
для "модифицированных" репозиториев. Первый символ выходных строк указывает на это. Если суб-репо изменен, вы НЕ МОЖЕТЕ продолжить. - для каждого репо в списке, перейдите в его каталог и запустите
git checkout master && git pull
, Проверьте на ошибки. - В конце я предлагаю вам распечатать дисплей для отображения текущего статуса подмодулей - возможно, предложить им добавить все и зафиксировать?
Я хотел бы отметить, что этот стиль не совсем то, для чего были созданы подмодули 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 г.)
коммит 6f65f84
submodule
: принять команду обновленияПодписал: Свен Стрикрот
Начиная с 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
.
Посмотрите на 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 или другого скриптового языка, отличного от пакетного, позволит вам легко добавлять / удалять подпроекты без необходимости изменять скрипт.