Łatwy sposób na pobranie najnowszych wszystkich podmodułów git

1846

Używamy podmodułów git do zarządzania kilkoma dużymi projektami, które są zależne od wielu innych bibliotek, które opracowaliśmy. Każda biblioteka stanowi osobne repozytorium wprowadzone do projektu zależnego jako podmoduł. Podczas opracowywania często chcemy po prostu pobrać najnowszą wersję każdego zależnego podmodułu.

Czy git ma wbudowane polecenie, aby to zrobić? Jeśli nie, to co powiesz na plik wsadowy Windows lub podobny, który może to zrobić?

Brad Robinson
źródło
git-deep powinien w tym pomóc.
Mathew Kurian
9
@Brad, czy chcesz zaktualizować swoje kopie podmodułów do wersji zatwierdzania wymienionych w projekcie głównym; czy chcesz pobrać najnowsze zatwierdzenie HEAD z każdego podmodułu? Większość odpowiedzi tutaj dotyczy pierwszej; wiele osób chce tego drugiego.
chrisinmtown

Odpowiedzi:

2462

Jeśli po raz pierwszy sprawdzasz repozytorium, musisz --initnajpierw użyć :

git submodule update --init --recursive

W przypadku wersji Git 1.8.2 lub nowszej --remotedodano opcję obsługi aktualizacji do najnowszych wskazówek zdalnych gałęzi:

git submodule update --recursive --remote

Ma to tę dodatkową zaletę, że szanuje dowolne gałęzie „inne niż domyślne” określone w plikach .gitmoduleslub .git/config(jeśli tak się dzieje, domyślną wartością jest origin / master, w którym to przypadku niektóre inne odpowiedzi tutaj również działałyby).

W przypadku wersji git 1.7.3 lub nowszej możesz użyć (ale poniższe informacje wokół tego, co nadal obowiązuje aktualizacja):

git submodule update --recursive

lub:

git pull --recurse-submodules

jeśli chcesz wyciągnąć submoduły do ​​najnowszych zatwierdzeń zamiast bieżącego zatwierdzenia punktów repo.

Zobacz git-submodule (1) szczegóły

Henrik Gustafsson
źródło
299
Prawdopodobnie powinieneś git submodule update --recursivedzisiaj używać .
Jens Kohl,
38
Poprawa wydajności:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev
18
aktualizacja zaktualizuje każdy podmoduł do określonej wersji, a nie zaktualizuje go do najnowszej wersji dla tego repozytorium.
Peter DeWeese,
21
Wystarczy dodać, że ślepe przyklejenie origin masterna końcu tego polecenia może przynieść nieoczekiwane rezultaty, jeśli niektóre z podmodułów śledzą inną nazwę gałęzi lub lokalizacji tego konkretnego podmodułu. Oczywiste dla niektórych, ale prawdopodobnie nie dla wszystkich.
Nathan Hornby
31
Tylko dla wyjaśnienia. git submodule update --recursivesprawdza, która wersja przechowywana jest w repozytorium nadrzędnym dla każdego podmodułu, a następnie sprawdza tę wersję w każdym podmodule. Robi NIE ciągnąć najnowsze rewizje dla każdego modułem. git submodule foreach git pull origin masterlub git pull origin master --recurse-submodulesjest tym, czego chcesz, jeśli zamierzasz zaktualizować każdy podmoduł do najnowszych z repozytoriów pochodzenia. Tylko wtedy otrzymasz oczekujące zmiany w repozytorium nadrzędnym ze zaktualizowanymi skrótami wersji dla podmodułów. Zamelduj się i jesteś dobry.
Chev
636
git pull --recurse-submodules --jobs=10

funkcja git po raz pierwszy nauczyła się w 1.8.5.

Dopóki błąd nie zostanie naprawiony, po raz pierwszy musisz uruchomić

git submodule update --init --recursive

Alexander Bartosh
źródło
29
w górę, korzystam z tego: alias update_submodules = 'git pull --recurse-submodules && git submodule update'
Stephen C
3
Działa to, jeśli submoduły zostały już ściągnięte przynajmniej raz, ale dla submodułów, które nigdy nie zostały sprawdzone, patrz odpowiedź gahooa poniżej.
Matt Browne
8
Spowoduje to wyświetlenie wersji określonej przez najlepsze repozytorium; NIE ciągnie HEAD. Na przykład, jeśli TopRepo określi wersję 2 za HEAD dla SubRepo, pociągnie to SubRepo z tą wersją, która ma 2 z tyłu. Inne odpowiedzi tutaj ściągnij HEAD w SubRepo.
Chris Moschini,
11
Zauważ, że ani git pull --recurse-submodulesani git submodule update --recursivenie nie initialize nowo dodany submodules. Aby je zainicjować, musisz uruchomić git submodule update --recursive --init. Cytat z instrukcji : Jeśli podmoduł nie jest jeszcze zainicjowany, a chcesz po prostu użyć ustawienia zapisanego w .gitmodules, możesz automatycznie zainicjować podmoduł za pomocą opcji --init.
patryk.beza
1
może dodać wskazówkę, do git submodule update --recursive --remotektórej aktualizuje również podmoduły do ​​najnowszej zdalnej wersji zamiast przechowywanego SHA-1.
Hanno S.,
386

Przy inicjowaniu uruchom następujące polecenie:

git submodule update --init --recursive

z katalogu git repo działa najlepiej dla mnie.

Spowoduje to wyciągnięcie wszystkich najnowszych, w tym podmodułów.

Wyjaśnione

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.

Następnie możesz po prostu uruchomić:

git submodule update --recursive

z katalogu git repo działa najlepiej dla mnie.

Spowoduje to wyciągnięcie wszystkich najnowszych, w tym podmodułów.

abc123
źródło
10
Tak - najlepiej głosowana odpowiedź była najlepszym sposobem na zrobienie tego w 2009 roku, ale teraz jest to zdecydowanie prostsze i bardziej intuicyjne.
Michael Scott Cuthbert,
2
@MichaelScottCuthbert dzięki, jestem pewien, że za kolejne 3 lata to polecenie też będzie szalone
abc123
5
Niemniej jednak nie pobiera to najnowszej wersji z podmodułu, a jedynie najnowszą wersję, którą śledzi rodzic.
Nathan Osman,
4
@NathanOsman, który jest tym, czego chcesz ... skończysz z uszkodzonym kodem, nie przestrzegając śledzenia wersji rodziców. Jeśli jesteś opiekunem rodzica, możesz je zaktualizować i zatwierdzić.
abc123
2
Tak, ale z mojego zrozumienia, nie tego chciał OP.
Nathan Osman,
305

Uwaga: pochodzi z 2009 roku i może wtedy było dobrze, ale teraz są lepsze opcje.

Używamy tego. To się nazywa 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

Po prostu umieść go w odpowiednim katalogu bin (/ usr / local / bin). W systemie Windows konieczna może być modyfikacja składni, aby działała :)

Aktualizacja:

W odpowiedzi na komentarz oryginalnego autora o wciągnięciu wszystkich HEADÓW wszystkich submodułów - to dobre pytanie.

Jestem całkiem pewien, że wewnętrznie gitnie ma na to polecenia. Aby to zrobić, musisz określić, czym tak naprawdę jest HEAD dla submodułu. To może być tak proste, jak powiedzenie, że masterjest to najbardziej aktualna gałąź itp.

Następnie utwórz prosty skrypt, który wykonuje następujące czynności:

  1. sprawdź git submodule status„zmodyfikowane” repozytoria. Wskazuje na to pierwszy znak linii wyjściowych. Jeśli sub-repo zostanie zmodyfikowane, możesz NIE chcieć kontynuować.
  2. dla każdego wymienionego repo, włóż CD do jego katalogu i uruchom git checkout master && git pull. Sprawdź błędy.
  3. Na koniec sugeruję wydrukowanie wyświetlacza dla użytkownika, aby wskazać aktualny status submodułów - być może poprosić go o dodanie wszystkich i zatwierdzenie?

Chciałbym wspomnieć, że ten styl nie jest tak naprawdę przeznaczony dla podmodułów git. Zazwyczaj chcesz powiedzieć, że „LibraryX” jest w wersji „2.32” i tak pozostanie, dopóki nie powiem „zaktualizować”.

W pewnym sensie robisz to z opisanym skryptem, ale tylko bardziej automatycznie. Wymagana jest ostrożność!

Aktualizacja 2:

Jeśli korzystasz z platformy Windows, możesz rozważyć użycie Pythona do implementacji skryptu, ponieważ jest on bardzo zdolny w tych obszarach. Jeśli korzystasz z Uniksa / Linuksa, sugeruję tylko skrypt bash.

Potrzebujesz wyjaśnień? Po prostu opublikuj komentarz.

gahooa
źródło
Nie sądzę, że tego chcę. Czy nie spowoduje to ściągnięcia wersji podmodułów, z którymi ostatni projekt został ostatnio popełniony. Chcę wyciągnąć główną wersję wszystkich submodułów.
Brad Robinson
3
Działa to świetnie i działa nie tylko w celu aktualizacji submodułów, ale także pobrania ich po raz pierwszy, jeśli tego potrzebujesz.
Matt Browne
Właśnie otrzymuję komunikat „Brak informacji o śledzeniu dla bieżącego oddziału. Proszę określić, z którym odgałęzieniem chcesz się połączyć”. Bez względu na to, co spróbuję: /
Nathan Hornby
9
Dlaczego nie stworzyć dla niego aliasu? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'a następnie użyj go jak git pupbez skryptów.
fracz
Dziękuję, z jakiegoś powodu, mimo że mam git 1.9.1, musiałem wykonać git submodule initpo pierwszym ściągnięciu z dołączonymi podmodułami, aby wszystko zaczęło działać poprawnie.
Ben Usman,
164

Henrik jest na dobrej drodze. Polecenie „foreach” może wykonać dowolny dowolny skrypt powłoki. Mogą być dwie opcje pobrania najnowszej wersji,

git submodule foreach git pull origin master

i,

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

Spowoduje to iterację wszystkich zainicjowanych podmodułów i uruchomienie podanych poleceń.

mturquette
źródło
144

Poniższe działało dla mnie w systemie Windows.

git submodule init
git submodule update
zachleat
źródło
6
Wyraźnie nie o to prosił PO. Zostanie zaktualizowany tylko do zatwierdzonego podmodułu, a nie do najnowszego.
Patrick,
52
Jest to jednak jedyna rzecz na tej stronie, która skłoniła mnie do
pobrania
2
Można również użyć: git submodule update --init --recursive (szczególnie, jeśli dany moduł jest RestKit ze świeżego klonu)
HCdev
33

Edytuj :

W komentarzach wskazano (przez philfreo ), że wymagana jest najnowsza wersja. Jeśli są jakieś zagnieżdżone podmoduły, które muszą być w najnowszej wersji:

git submodule foreach --recursive git pull

----- Nieaktualny komentarz poniżej -----

Czy to nie jest oficjalny sposób na zrobienie tego?

git submodule update --init

Używam go za każdym razem. Jak dotąd żadnych problemów.

Edytować:

Właśnie odkryłem, że możesz użyć:

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

Który również rekurencyjnie wyciągnie wszystkie submoduły, tj. Zależności.

antytoksyczny
źródło
5
Twoja odpowiedź nie odpowiada na pytanie PO, ale aby zrobić to, co zaproponowałeś, możesz po prostu powiedziećgit submodule update --init --recursive
philfreo
2
Rozumiem, potrzebna jest najnowsza wersja. Może to być przydatne, jeśli istnieją zagnieżdżone submoduły: git submodule foreach --recursive git pull
antytoksyczny
1
Nie mogłem zmusić żadnego z nich do pobrania niczego - działała jednak dla mnie „aktualizacja git submodule --init --recursive”.
BrainSlugs83
33

Ponieważ może się zdarzyć, że domyślna gałąź twoich submodułów nie master jest, tak automatyzuję pełne aktualizacje Git modułów:

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'
Sebastien Varrette
źródło
spośród wielu odpowiedzi na wiele pytań, to zadziałało dla mnie (2019, błąd github z określonymi identyfikatorami mieszania)
Philshem
30

Pierwszy raz

Podmoduł klonowania i inicjowania

git clone [email protected]:speedovation/kiwi-resources.git resources
git submodule init

Reszta

Podczas programowania wystarczy pobrać i zaktualizować submoduł

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

Zaktualizuj podmoduł Git do najnowszej wersji zatwierdzenia na początku

git submodule foreach git pull origin master

Preferowany sposób powinien być poniżej

git submodule update --remote --merge

Uwaga: ostatnie dwa polecenia mają takie samo zachowanie

Yash
źródło
Zrobiłem przez pomyłkę klon bez podmodułów i wszystkie inne opcje nie zadziałały, nikt nie klonował podmodułów. Używając twojego, git submodule updatezałatwiłem sprawę. Teraz pobieram brak danych podmodułów w pierwszym kroku klonowania. Dziękuję Ci. Nie jestem dobry w git: C
m3nda
Ten anser jest w rzeczywistości bardzo dobrą odpowiedzią na postawienie pytania tutaj: dlaczego muszę „.. - rekursywne-submoduły ..”, a następnie dodatkowo „... aktualizacja ...”, a nawet „.. .foreach ... "później, aby uzyskać najnowsze zatwierdzenie? Wszystko to wcale nie wygląda jak GIT! Co robi „aktualizacja” i dlaczego muszę ręcznie przejść do każdego modułu, aby go pobrać? Czy to nie to, co robi „… --recurse-submodules ..”? Jakieś wskazówki?
Peter Branforn,
20

Nie wiem, od której wersji git to działa, ale właśnie tego szukasz:

git submodule update --recursive

Używam go również git pulldo aktualizacji repozytorium głównego:

git pull && git submodule update --recursive
Jens Kohl
źródło
10

Powyższe odpowiedzi są dobre, jednak używaliśmy haczyków git, aby to ułatwić, ale okazuje się, że w git 2.14 można ustawić wartość git config submodule.recursetrue, aby umożliwić aktualizację podmodułów po przejściu do repozytorium git.

Będzie to miało efekt uboczny polegający na wypychaniu wszystkich podmodułów, które masz, jeśli są one jednak na gałęziach, ale jeśli potrzebujesz tego zachowania już to może zrobić.

Można to zrobić za pomocą:

git config submodule.recurse true
JamesD
źródło
Uwielbiam tę opcję, niestety nadal musisz jej użyć git submodule initprzed ręką, jeśli twój podmoduł nie jest jeszcze zainicjowany.
Pellet
5

Git dla systemu Windows 2.6.3 :

git submodule update --rebase --remote

Seul
źródło
To jedyny, który pracował dla mnie. Nie byłem nawet w stanie zainicjować ani zaktualizować, ponieważ wskaźnik submodułu wskazywał na wersję, której już nie ma w zdalnej wersji
Pavel P
4

Z najwyższego poziomu w repozytorium:

git submodule foreach git checkout develop
git submodule foreach git pull

Spowoduje to zmianę wszystkich gałęzi w celu rozwijania i pobierania najnowszych

Srayan Guhathakurta
źródło
2
Nie działa dla mnie z git 2.7.
Bruno Haible
Czy masz coś w rodzaju pliku SLN Everything, który dodaje wszystkie odwołania do projektu w drzewie? Jaki błąd widzisz? Czy możesz także sprawdzić plik
gitignore
1
git submodule foreach git pull origin masterMusiałem dołączyć gałąź, którą chciałem pobrać. poza tym działał idealnie.
Torxed
3

Zrobiłem to poprzez dostosowanie gahooa „s odpowiedź powyżej :

Zintegruj go z git [alias]...

Jeśli twój projekt nadrzędny ma coś takiego .gitmodules:

[submodule "opt/submodules/solarized"]
    path = opt/submodules/solarized
    url = [email protected]:altercation/solarized.git
[submodule "opt/submodules/intellij-colors-solarized"]
    path = opt/submodules/intellij-colors-solarized
    url = [email protected]:jkaving/intellij-colors-solarized.git

Dodaj coś takiego w .gitconfig

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

Następnie, aby zaktualizować submoduły, uruchom:

git updatesubs

Mam taki przykład w moim repozytorium konfiguracji środowiska .

Tomek
źródło
3

Wszystko, co musisz teraz zrobić, to proste git checkout

Pamiętaj tylko, aby włączyć tę funkcję za pomocą tej globalnej konfiguracji: git config --global submodule.recurse true

Śrut
źródło
2

Oto wiersz polecenia do pobrania ze wszystkich repozytoriów git, niezależnie od tego, czy są one podmodułami:

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

Jeśli uruchamiasz go w swoim najlepszym repozytorium git, możesz go zamienić "$ROOT"na ..

kenorb
źródło
1

Myślę, że będziesz musiał napisać skrypt, aby to zrobić. Aby być uczciwym, mogę zainstalować python to zrobić tak, że można użyć os.walkdo cdkażdego katalogu i wydać odpowiednie polecenia. Użycie Pythona lub innego języka skryptowego, innego niż wsadowy, pozwoliłoby na łatwe dodawanie / usuwanie podprojektów bez konieczności modyfikowania skryptu.

baudtack
źródło
1

Uwaga: niezbyt łatwy sposób, ale wykonalny i ma swoje własne unikalne zalety.

Jeśli chce się sklonować tylko HEADwersję repozytorium i tylko HEADs wszystkich jego podmodułów (tj. Do kasy „trunk”), można użyć następującego skryptu Lua . Czasami proste polecenie git submodule update --init --recursive --remote --no-fetch --depth=1może spowodować nieodwracalny gitbłąd. W takim przypadku należy .git/modulesręcznie wyczyścić podkatalog katalogu i sklonować podmoduł za pomocą git clone --separate-git-dirpolecenia. Jedyną złożonością jest znalezienie adresu URL , ścieżki .gitkatalogu submodułu i ścieżki submodułu w drzewie superprojektu.

Uwaga: skrypt jest testowany tylko na https://github.com/boostorg/boost.gitrepozytorium. Jego osobliwości: wszystkie submoduły hostowane na tym samym hoście i .gitmoduleszawierają tylko względne adresy 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
Tomiłow Anatolij
źródło