Einfache Möglichkeit, die neuesten Git-Submodule zu ziehen

1846

Wir verwenden Git-Submodule, um einige große Projekte zu verwalten, die von vielen anderen von uns entwickelten Bibliotheken abhängig sind. Jede Bibliothek ist ein separates Repo, das als Submodul in das abhängige Projekt gebracht wird. Während der Entwicklung möchten wir oft nur die neueste Version jedes abhängigen Submoduls herunterladen.

Hat git einen eingebauten Befehl, um dies zu tun? Wenn nicht, wie wäre es mit einer Windows-Batchdatei oder ähnlichem, die dies kann?

Brad Robinson
quelle
git-deep sollte dabei helfen.
Mathew Kurian
9
@Brad möchten Sie Ihre Kopien von Submodulen auf die im Master-Projekt angegebenen Commit-Revs aktualisieren? oder möchten Sie das neueste HEAD-Commit von jedem Submodul abrufen? Die meisten Antworten hier beziehen sich auf die ersteren; viele Leute wollen Letzteres.
Chrisinmtown

Antworten:

2464

Wenn Sie zum ersten Mal ein Repo auschecken, müssen Sie es --initzuerst verwenden:

git submodule update --init --recursive

Für Git 1.8.2 oder höher wurde die Option --remotehinzugefügt, um die Aktualisierung auf die neuesten Tipps für Remote-Zweige zu unterstützen:

git submodule update --recursive --remote

Dies hat den zusätzlichen Vorteil, dass alle in den .gitmodulesoder .git/config-Dateien angegebenen "Nicht-Standard" -Zweige berücksichtigt werden (wenn Sie zufällig einen haben, ist der Standard "Ursprung / Master". In diesem Fall würden auch einige der anderen Antworten hier funktionieren).

Für Git 1.7.3 oder höher können Sie Folgendes verwenden (aber die folgenden Fallstricke zeigen an, welches Update noch gilt):

git submodule update --recursive

oder:

git pull --recurse-submodules

Wenn Sie Ihre Submodule auf die neuesten Commits anstatt auf das aktuelle Commit ziehen möchten, zeigt das Repo auf.

Siehe Git-Submodul (1) für Details

Henrik Gustafsson
quelle
299
Wahrscheinlich sollten Sie git submodule update --recursiveheutzutage verwenden.
Jens Kohl
38
Leistungsverbesserung:git submodule foreach "(git checkout master; git pull)&"
Bogdan Gusiev
18
update aktualisiert jedes Submodul auf die angegebene Revision und nicht auf die neueste Version für dieses Repository.
Peter DeWeese
21
Nur um hinzuzufügen, kann das blinde Festhalten origin masteram Ende dieses Befehls zu unerwarteten Ergebnissen führen, wenn einige Ihrer Submodule einen anderen Zweig- oder Standortnamen dieses bestimmten Submoduls verfolgen. Für einige offensichtlich, aber wahrscheinlich nicht für alle.
Nathan Hornby
31
Nur um es für alle zu klären. git submodule update --recursivePrüft, welche Revision das übergeordnete Repository für jedes Submodul gespeichert hat, und überprüft dann diese Revision in jedem Submodul. Es werden NICHT die neuesten Commits für jedes Submodul abgerufen. git submodule foreach git pull origin masteroder git pull origin master --recurse-submodulesist das, was Sie möchten, wenn Sie beabsichtigen, jedes Submodul aus seinen Ursprungs-Repositorys auf den neuesten Stand zu bringen. Nur dann erhalten Sie ausstehende Änderungen im übergeordneten Repo mit aktualisierten Revisions-Hashes für Submodule. Checken Sie diese ein und Sie sind gut.
Chev
636
git pull --recurse-submodules --jobs=10

Ein Feature-Git, das zuerst in 1.8.5 gelernt wurde.

Bis der Fehler behoben ist, müssen Sie zum ersten Mal ausführen

git submodule update --init --recursive

Alexander Bartosh
quelle
29
upvoted, ich benutze dies: alias update_submodules = 'git pull --recurse-submodules && git submodule update'
Stephen C
3
Dies funktioniert, wenn die Submodule bereits mindestens einmal gezogen wurden, aber für Submodule, die noch nie ausgecheckt wurden, siehe Gahooas Antwort unten.
Matt Browne
8
Dadurch wird die vom Top-Repo angegebene Version erreicht. es zieht NICHT KOPF. Wenn TopRepo beispielsweise eine Version 2 hinter HEAD für SubRepo angibt, wird SubRepo mit der Version 2 hinter sich gezogen. Andere Antworten hier ziehen HEAD in SubRepo.
Chris Moschini
11
Beachten Sie, dass weder git pull --recurse-submodulesnoch git submodule update --recursivenicht nicht initialize neu Submodule hinzugefügt. Um sie zu initialisieren, müssen Sie ausführen git submodule update --recursive --init. Zitat aus dem Handbuch : Wenn das Submodul noch nicht initialisiert ist und Sie nur die in .gitmodules gespeicherte Einstellung verwenden möchten, können Sie das Submodul automatisch mit der Option --init initialisieren.
patryk.beza
1
Fügen Sie möglicherweise einen Hinweis hinzu, git submodule update --recursive --remoteder anstelle des gespeicherten SHA-1 auch die Submodule auf die neueste Remote-Version aktualisiert.
Hanno S.
386

Führen Sie auf init den folgenden Befehl aus:

git submodule update --init --recursive

funktioniert aus dem git repo verzeichnis am besten für mich.

Dadurch werden alle neuesten Modelle einschließlich Submodule abgerufen.

Erklärt

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.

Danach können Sie einfach ausführen:

git submodule update --recursive

funktioniert aus dem git repo verzeichnis am besten für mich.

Dadurch werden alle neuesten Modelle einschließlich Submodule abgerufen.

abc123
quelle
10
Ja - die Antwort mit der höchsten Stimme war der beste Weg, dies in '09 zu tun, aber dies ist jetzt definitiv einfacher und intuitiver.
Michael Scott Cuthbert
2
@ MichaelScottCuthbert danke, ich bin sicher, dass dieser Befehl in weiteren 3 Jahren auch verrückt sein wird
abc123
5
Dies überprüft jedoch nicht die neueste Version des Submoduls, sondern nur die letzte Version, die das übergeordnete Element verfolgt.
Nathan Osman
4
@NathanOsman, was Sie wollen ... Sie werden mit defektem Code enden, wenn Sie dem Revisions-Tracking der Eltern nicht folgen. Wenn Sie der Betreuer des übergeordneten Elements sind, können Sie diese selbst aktualisieren und festschreiben.
abc123
2
Ja, aber nach meinem Verständnis wollte das OP das nicht.
Nathan Osman
305

Hinweis: Dies ist aus dem Jahr 2009 und war damals vielleicht gut, aber jetzt gibt es bessere Optionen.

Wir nutzen dies. Es heißt 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

Legen Sie es einfach in ein geeignetes bin-Verzeichnis (/ usr / local / bin). Unter Windows müssen Sie möglicherweise die Syntax ändern, damit es funktioniert :)

Aktualisieren:

Als Antwort auf den Kommentar des ursprünglichen Autors zum Einziehen aller KÖPFE aller Submodule - das ist eine gute Frage.

Ich bin mir ziemlich sicher, dass gites intern keinen Befehl dafür gibt. Dazu müssten Sie herausfinden, was HEAD wirklich für ein Submodul ist. Das könnte so einfach sein, als würde man sagen, es mastersei der aktuellste Zweig usw.

Erstellen Sie anschließend ein einfaches Skript, das Folgendes ausführt:

  1. Suchen Sie git submodule statusnach "geänderten" Repositorys. Das erste Zeichen der Ausgabezeilen zeigt dies an. Wenn ein Sub-Repo geändert wird, möchten Sie möglicherweise NICHT fortfahren.
  2. CD für jedes aufgelistete Repo in sein Verzeichnis legen und ausführen git checkout master && git pull. Auf Fehler prüfen.
  3. Am Ende schlage ich vor, dass Sie dem Benutzer eine Anzeige drucken, um den aktuellen Status der Submodule anzuzeigen. Fordern Sie ihn möglicherweise auf, alle hinzuzufügen und festzuschreiben.

Ich möchte erwähnen, dass dieser Stil nicht wirklich das ist, wofür Git-Submodule entwickelt wurden. Normalerweise möchten Sie sagen, dass "LibraryX" die Version "2.32" hat und so bleibt, bis ich ihm sage, dass er "upgraden" soll.

In gewisser Weise machen Sie das mit dem beschriebenen Skript, aber nur automatischer. Vorsicht ist geboten!

Update 2:

Wenn Sie sich auf einer Windows-Plattform befinden, sollten Sie Python verwenden, um das Skript zu implementieren, da es in diesen Bereichen sehr leistungsfähig ist. Wenn Sie unter Unix / Linux arbeiten, empfehle ich nur ein Bash-Skript.

Benötigen Sie Klarstellungen? Schreibe einfach einen Kommentar.

gahooa
quelle
Ich glaube nicht, dass ich das will. Wird das nicht die Version der Submodule ziehen, mit denen das Superprojekt zuletzt festgeschrieben wurde? Ich möchte die Kopfversion aller Submodule ziehen.
Brad Robinson
3
Dies funktioniert hervorragend und funktioniert nicht nur, um die Submodule zu aktualisieren, sondern auch, um sie zum ersten Mal abzurufen, wenn Sie dies benötigen.
Matt Browne
Ich erhalte nur die Meldung "Es gibt keine Tracking-Informationen für den aktuellen Zweig. Bitte geben Sie an, mit welchem ​​Zweig Sie zusammenführen möchten." Egal was ich versuche: /
Nathan Hornby
9
Warum nicht einen Alias ​​dafür erstellen? git config --global alias.pup '!git pull && git submodule init && git submodule update && git submodule status'und dann wie git pupohne Scripting verwenden.
Fracz
Vielen Dank, aus irgendeinem Grund, obwohl ich Git 1.9.1 habe, musste ich git submodule initnach dem ersten Pull mit Submodulen ausführen , damit alles richtig funktioniert.
Ben Usman
164

Henrik ist auf dem richtigen Weg. Der Befehl 'foreach' kann ein beliebiges Shell-Skript ausführen. Zwei Optionen, um die neuesten zu ziehen, könnten sein:

git submodule foreach git pull origin master

und,

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

Dadurch werden alle initialisierten Submodule durchlaufen und die angegebenen Befehle ausgeführt.

mturquette
quelle
144

Folgendes hat bei mir unter Windows funktioniert.

git submodule init
git submodule update
zachleat
quelle
6
Dies ist eindeutig nicht das, was das OP verlangt hat. Es wird nur auf das zugehörige Submodul-Commit aktualisiert und nicht auf das neueste.
Patrick
52
Dies ist jedoch das einzige, was auf dieser Seite dazu gebracht wurde, Submodule zu ziehen, als ich zum ersten Mal ein Repo
auscheckte
2
Kann auch verwenden: git Submodul Update --init --recursive (insbesondere wenn das fragliche Submodul RestKit von einem neuen Klon ist)
HCdev
33

Bearbeiten :

In den Kommentaren wurde (von philfreo ) darauf hingewiesen, dass die neueste Version erforderlich ist. Wenn verschachtelte Submodule in der neuesten Version vorhanden sein müssen:

git submodule foreach --recursive git pull

----- Veralteter Kommentar unten -----

Ist das nicht der offizielle Weg, es zu tun?

git submodule update --init

Ich benutze es jedes Mal. Bisher keine Probleme.

Bearbeiten:

Ich habe gerade festgestellt, dass Sie verwenden können:

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

Dadurch werden auch alle Submodule, dh Abhängigkeiten, rekursiv abgerufen.

antitoxisch
quelle
5
Ihre Antwort beantwortet nicht die Frage des OP, aber um das zu tun, was Sie vorgeschlagen haben, können Sie einfach sagengit submodule update --init --recursive
Philfreo
2
Ich sehe, die neueste Version wird benötigt. Nun, dies könnte nützlich sein, wenn es verschachtelte Submodule gibt: git submodule foreach --recursive git pull
Antitoxikum
1
Ich konnte keines davon zum Herunterladen bringen - "git submodule update --init --recursive" funktionierte jedoch für mich.
BrainSlugs83
33

Da es vorkommen kann, dass der Standardzweig Ihrer Submodule nicht master lautet, automatisiere ich auf diese Weise die vollständigen Git-Submodul-Upgrades:

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
quelle
Von den vielen Antworten auf die vielen Fragen hat diese für mich funktioniert (2019, Github-Fehler mit bestimmten Hash-IDs)
Philshem
30

Erstes Mal

Submodul klonen und initialisieren

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

Sich ausruhen

Während der Entwicklung einfach das Submodul ziehen und aktualisieren

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

Aktualisieren Sie das Git-Submodul auf das neueste Commit für den Ursprung

git submodule foreach git pull origin master

Der bevorzugte Weg sollte unten sein

git submodule update --remote --merge

Hinweis: Die letzten beiden Befehle haben dasselbe Verhalten

Yash
quelle
Ich habe versehentlich einen Git-Klon ohne Submodule erstellt und alle anderen Optionen haben nicht funktioniert. Niemand hat Submodule geklont. Hat deinen git submodule updateTrick gemacht. Jetzt lade ich Submoduldaten herunter, die im ersten Schritt des Klons fehlen. Vielen Dank. Ich bin nicht gut in git: C
m3nda
Dieser Anser ist eigentlich eine sehr gute Antwort, um hier oben eine Frage zu stellen: Warum muss ich ".. --recursive-submodules .." und dann zusätzlich das "... update ..." und sogar ".. .foreach ... "später, um das neueste Commit zu erhalten? All dies sieht überhaupt nicht nach GIT aus! Was macht "Update" und warum muss ich manuell zu jedem Modul gehen, um es abzurufen? Ist es nicht das, was "... --recurse-submodules .." tut? Irgendwelche Hinweise?
Peter Branforn
20

Ich weiß nicht, seit welcher Version von Git dies funktioniert, aber das ist es, wonach Sie suchen:

git submodule update --recursive

Ich benutze es auch git pull, um das Root-Repository zu aktualisieren:

git pull && git submodule update --recursive
Jens Kohl
quelle
10

Die obigen Antworten sind gut, wir haben jedoch Git-Hooks verwendet, um dies zu vereinfachen. Es stellt sich jedoch heraus, dass Sie in Git 2.14git config submodule.recurse den Wert true festlegen können , damit Submodule aktualisiert werden können, wenn Sie in Ihr Git-Repository ziehen.

Dies hat den Nebeneffekt, dass alle Änderungen an Submodulen, die Sie haben, verschoben werden, wenn sie sich in Zweigen befinden. Wenn Sie dieses Verhalten jedoch bereits benötigen, kann dies den Job erledigen.

Kann durchgeführt werden mit:

git config submodule.recurse true
JamesD
quelle
Ich muss diese Option lieben, muss sie aber leider noch git submodule initvorher verwenden, wenn Ihr Submodul noch nicht initialisiert ist.
Pellet
5

Git für Windows 2.6.3 :

git submodule update --rebase --remote

Seoul
quelle
Das ist der einzige, der für mich funktioniert hat. Ich konnte nicht einmal initiieren oder aktualisieren, da der Submodulzeiger auf eine Version zeigte, die sich nicht mehr in der Fernbedienung befand
Pavel P
4

Von der obersten Ebene im Repo:

git submodule foreach git checkout develop
git submodule foreach git pull

Dadurch werden alle Zweige auf die Entwicklung und den neuesten Stand umgestellt

Srayan Guhathakurta
quelle
2
Funktioniert bei mir nicht, mit git 2.7.
Bruno Haible
Haben Sie so etwas wie eine Everything sln-Datei, die alle Projektreferenzen in den Baum einfügt? Auch welchen Fehler sehen Sie? Können Sie auch Ihre Gitignore-Datei überprüfen
Srayan Guhathakurta
1
git submodule foreach git pull origin masterMusste den Zweig anhängen, den ich holen wollte. ansonsten funktionierte perfekt.
Torxed
3

Ich habe dies getan , indem ich die Antwort von Gahooa oben angepasst habe :

Integriere es mit einem Git [alias]...

Wenn Ihr übergeordnetes Projekt Folgendes hat .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

Fügen Sie so etwas in Ihre .gitconfig ein

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

Führen Sie dann zum Aktualisieren Ihrer Submodule Folgendes aus:

git updatesubs

Ich habe ein Beispiel dafür in meinem Umgebungs-Setup-Repo .

Tom
quelle
3

Alles was Sie jetzt tun müssen, ist eine einfache git checkout

Stellen Sie einfach sicher, dass Sie es über diese globale Konfiguration aktivieren: git config --global submodule.recurse true

Pellet
quelle
2

Hier ist die Befehlszeile, mit der Sie aus allen Git-Repositorys abrufen können, ob es sich um Submodule handelt oder nicht:

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

Wenn Sie es in Ihrem Top-git - Repository ausgeführt wird , können Sie ersetzen "$ROOT"in ..

Kenorb
quelle
1

Ich denke, Sie müssen ein Skript schreiben, um dies zu tun. Um ehrlich zu sein, könnte ich installieren Python es so zu tun , dass Sie verwenden können , os.walkum cdzu jedem Verzeichnis und die entsprechenden Befehle erteilen. Wenn Sie Python oder eine andere Skriptsprache als Batch verwenden, können Sie problemlos Unterprojekte hinzufügen / entfernen, ohne das Skript ändern zu müssen.

Baudtack
quelle
1

Bemerkung: nicht allzu einfach, aber praktikabel und es hat seine eigenen einzigartigen Profis.

Wenn man nur die HEADRevision eines Repositorys und nur HEADs aller seiner Submodule klonen möchte (dh "Trunk" auschecken), kann man das folgende Lua- Skript verwenden. Manchmal git submodule update --init --recursive --remote --no-fetch --depth=1kann ein einfacher Befehl zu einem nicht behebbaren gitFehler führen. In diesem Fall muss das Unterverzeichnis des .git/modulesVerzeichnisses bereinigt und das Submodul manuell mit dem git clone --separate-git-dirBefehl geklont werden . Die einzige Komplexität besteht darin, die URL , den Pfad des .gitVerzeichnisses des Submoduls und den Pfad des Submoduls im Superprojektbaum herauszufinden .

Anmerkung: Das Skript wird nur gegen das https://github.com/boostorg/boost.gitRepository getestet . Seine Besonderheiten: Alle Submodule werden auf demselben Host gehostet und .gitmodulesenthalten nur relative URLs .

-- 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
Tomilov Anatoliy
quelle