Простий спосіб отримати найновіші з усіх підмодулів git


1846

Ми використовуємо підмодулі git для управління кількома великими проектами, які залежать від багатьох інших розроблених нами бібліотек. Кожна бібліотека - це окреме репо, введене у залежний проект як підмодуль. Під час розробки ми часто хочемо просто взяти останню версію кожного залежного підмодуля.

Чи має git вбудована команда для цього? Якщо ні, то як щодо пакетного файлу Windows чи подібного, що може це зробити?


git-deep повинен допомогти у цьому.
Матвій Куріан

9
@Brad ви хочете оновити свої копії підмодулів до випусків оборотів, зазначених у головному проекті; чи ви хочете витягнути останню комісію HEAD з кожного підмодуля? Більшість відповідей тут стосуються першої; багато людей хочуть останнього.
chrisinmtown

Відповіді:


2462

Якщо ви вперше перевіряєте репо, вам потрібно скористатися --initспочатку:

git submodule update --init --recursive

Для 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

якщо ви хочете перетягнути свої підмодулі до останніх комісій замість поточного фіксації, на яке вказують репо.

Див ГИТ-подмодуль (1) для отримання докладної інформації


299
Напевно, вам слід користуватися і git submodule update --recursiveсьогодні.
Єнс Кол

38
Покращення продуктивності:git submodule foreach "(git checkout master; git pull)&"
Богдан Гусієв

18
оновлення оновить кожен підмодуль до вказаної версії, не оновить його до останнього для цього сховища.
Peter DeWeese

21
Додамо лише, що сліпо вставляння origin masterв кінці цієї команди може мати несподівані результати, якщо деякі з ваших підмодулів відслідковують іншу гілку або назву місцезнаходження цього конкретного підмодуля. Очевидно для деяких, але, мабуть, не для всіх.
Натан Хорнбі

31
Просто для уточнення для всіх. git submodule update --recursiveшукає, яку редакцію зберігає батьківський репозиторій для кожного підмодуля, а потім перевіряє цю редакцію у кожному підмодулі. Він НЕ тягне останні коміти для кожного підмодуля. git submodule foreach git pull origin masterабо git pull origin master --recurse-submodulesце те, що ви хочете, якщо ви маєте намір оновити кожен підмодуль до останнього зі своїх сховищ походження. Тільки тоді ви отримаєте очікувані зміни в батьківській репо-версії з оновленими хешами версій для підмодулів. Перевірте це, і ви добре.
Шев

636
git pull --recurse-submodules --jobs=10

особливість git вперше дізналася в 1.8.5.

Поки помилка не виправлена, вперше вам потрібно запустити

оновлення підмодулю git --init --рекурсивне


29
прихильне, я використовую це: псевдонім update_submodules = 'git pull --рекурсивні підмодулі & & git оновлення субмодуля'
Stephen C

3
Це працює, якщо підмодулі вже витягнули принаймні один раз, але про підмодулі, які ніколи не перевірені, див. Відповідь gahooa нижче.
Метт Браун

8
Це підніметься до тієї версії, яку вказав верхній репо; він НЕ тягне голову. Наприклад, якщо TopRepo вказав версію 2 за HEAD для SubRepo, це потягне SubRepo з тією версією, яка 2 позаду. Інші відповіді тут тягнуть HEAD у SubRepo.
Кріс Москіні

11
Зверніть увагу , що ні один, git pull --recurse-submodulesні git submodule update --recursiveробить НЕ ініціалізації знову доданого подмодулей. Для їх ініціалізації потрібно запустити git submodule update --recursive --init. Цитата з посібника : Якщо підмодуль ще не ініціалізований, і ви просто хочете використовувати налаштування, збережені в .gitmodules, ви можете автоматично ініціалізувати підмодуль за допомогою параметра --init.
patryk.beza

1
можливо, додайте підказку, git submodule update --recursive --remoteяка також оновлює підмодулі до віддаленої останньої версії замість збереженої SHA-1.
Hanno S.

386

У програмі 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, найкраще працює для мене.

Це витягне всі останні, включаючи підмодулі.


10
Так - відповідь з найвищим голосом виявився найкращим способом зробити це у 09 році, але зараз це, безумовно, простіше та інтуїтивніше.
Майкл Скотт Катберт

2
@MichaelScottCuthbert дякую, я впевнений, що ще через 3 роки ця команда теж буде шаленою
abc123

5
Тим не менш, це не перевіряє останню редакцію з підмодуля, лише останню версію, яку відстежує батьків.
Натан Осман

4
@NathanOsman, що ви хочете ... ви в кінцевому підсумку зіпсували код, не дотримуючись відстеження ревізії батьків. Якщо ви підтримуєте батьків, ви можете оновити їх самі та взяти їх на себе.
abc123

2
Так, але, наскільки я розумію, це не те, чого хотіла ОП.
Натан Осман

305

Примітка. Це з 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

Просто помістіть його у відповідний каталог бін (/ 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.

Потрібні роз'яснення? Просто опублікуйте коментар.


Я не думаю, що це я хочу. Хіба це не потягне версію підмодулів, з якими останній раз був здійснений суперпроект. Я хочу витягнути головну версію всіх підмодулів.
Бред Робінсон,

3
Це чудово працює і працює не тільки для оновлення підмодулів, але і для їх першого внесення, якщо це те, що вам потрібно.
Метт Браун

Я просто отримую "Інформація відстеження для поточної гілки немає. Будь ласка, вкажіть, з якою гілкою ви хочете об'єднатись". Що б я не намагався: /
Натан Хорнбі

9
Чому б не створити псевдонім для цього? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'а потім використовувати його як git pupбез будь-якого сценарію.
фракц

Дякую, чомусь, хоча у мене є git 1.9.1, я повинен був виконати git submodule init після першого витягу, що включав підмодулі, щоб все почало працювати належним чином.
Бен Усман

164

Генрік на правильному шляху. Команда 'foreach' може виконати будь-який довільний сценарій оболонки. Можливо, два варіанти, щоб витягти найсвіжіші,

git submodule foreach git pull origin master

і,

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

Це дозволить повторити всі ініціалізовані підмодулі та виконати задані команди.


144

Наступне працювало для мене в Windows.

git submodule init
git submodule update

6
Очевидно, це не те, про що вимагала ОП. Він буде оновлюватися лише до асоційованого підкоду, а не останнього.
Патрік

52
Однак це єдине, що на цій сторінці отримало git для того, щоб витягнути підмодулі вперше, коли я перевірив репо,
theheadofabroom

2
Можна також використовувати: оновлення підмодуля git --init --рекурсивне (особливо, якщо підмодулем є RestKit зі свіжого клону)
HCdev

33

Редагувати :

У коментарях було вказано ( philfreo ), що потрібна остання версія. Якщо є вкладені підмодулі, які повинні бути в їх останній версії:

git submodule foreach --recursive git pull

----- Застарілий коментар нижче -----

Це не офіційний спосіб зробити це?

git submodule update --init

Я використовую його щоразу. Поки що жодних проблем.

Редагувати:

Щойно я виявив, що ви можете використовувати:

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

Що також буде рекурсивно витягувати всі підмодулі, тобто залежності.


5
Ваша відповідь не відповідає на питання ОП, але робити те, що ви запропонували, ви можете просто сказатиgit submodule update --init --recursive
philfreo

2
Я бачу, потрібна остання версія. Ну, це може бути корисним, якщо є вкладені підмодулі: git submodule foreach --recursive git pull
антитоксичний

1
Я не міг змусити нічого з цього фактично завантажити що-небудь - "оновлення підмодуля git - init - рекурсивне" працювало для мене, однак.
BrainSlugs83

33

Оскільки може трапитися, що гілка ваших підмодулів за замовчуванням не є 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'

з багатьох відповідей на багато питань, цей працював для мене (2019, github помилка з конкретними
хед-ідами

30

Перший раз

Клон та підмодуль Ініта

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

Примітка: останні дві команди мають однакову поведінку


Я зробив клон git без субмодулів помилково, і всі інші варіанти не спрацювали, ніхто не клонував підмодулі. Використовуючи своє, git submodule updateзробив трюк. Тепер я завантажую дані про підмодулі, відсутні у клону першого кроку. Дякую. Мені не добре в git: C
m3nda

Цей ансер насправді є дуже гарною відповіддю, щоб поставити запитання тут зверху: чому я повинен ".. --рекурсивно-підмодулі ..", а потім додатково "... оновлення ..." і навіть ".. .перед ... "пізніше, щоб отримати останню версію? Все це зовсім не виглядає як GIT! Що таке "оновлення", і чому мені потрібно вручну перейти до кожного модуля, щоб витягнути? Хіба це не те, що робить "... - повторні підмодулі .."? Якісь підказки?
Пітер Бранфорн

20

Я не знаю, з якої версії git це працює, але це те, що ви шукаєте:

git submodule update --recursive

Я використовую його git pullдля оновлення кореневого сховища:

git pull && git submodule update --recursive

10

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

Це призведе до побічного ефекту від натискання на всі зміни підмодулів, якщо вони є на гілках, але якщо у вас є така поведінка, це вже може зробити цю роботу.

Це можна зробити за допомогою:

git config submodule.recurse true

Подобається цей варіант, на жаль, все ще потрібно використовувати git submodule initперед рукою, хоча якщо ваш підмодуль ще не ініціалізований.
Пелет

5

Git для Windows 2.6.3 :

git submodule update --rebase --remote


Це єдиний, хто працював на мене. Я навіть не зміг ініціювати або оновити, оскільки вказівник підмодуля вказував на версію, якої вже не було у віддаленому режимі
Pavel P

4

З верхнього рівня в репо:

git submodule foreach git checkout develop
git submodule foreach git pull

Це дозволить переключити всі гілки на розвиток та витягнути останні


2
Не працює для мене, з git 2.7.
Бруно

Чи є у вас щось на кшталт файлу Everything sln, який додає всі посилання проекту на дерево? Також яку помилку ви бачите? Чи можете ви також перевірити свій файл
gitignore

1
git submodule foreach git pull origin masterДовелося додати гілку, яку я хотів отримати. крім цього, працював чудово.
Тортується

3

Я зробив це, адаптуючи gahooa «сек відповідь вище :

Інтегруйте його за допомогою git [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

Я маю приклад цього в репо-налаштуваннях оточення .


3

Все, що вам потрібно зробити зараз, - це просто git checkout

Просто переконайтеся, що ввімкнути це за допомогою цієї глобальної конфігурації: git config --global submodule.recurse true


2

Ось командний рядок, щоб витягнути з усіх ваших сховищ git незалежно від того, чи вони є субмодулами чи ні:

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

Якщо ви використовуєте його в верхньому сховище Git, ви можете замінити "$ROOT"в ..


1

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


1

Зауваження: не надто простий спосіб, але працездатний і у нього є свої неповторні плюси.

Якщо ви хочете клонувати лише HEADревізію сховища та лише HEADs усіх його підмодулів (тобто перевірити "магістраль"), тоді можна використовувати наступний скрипт 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.