Es scheint, als würden in dieser Diskussion zwei verschiedene Szenarien miteinander vermischt:
Szenario 1
Mit den Zeigern meines übergeordneten Repositorys auf Submodule möchte ich das Commit in jedem Submodul überprüfen, auf das das übergeordnete Repository verweist, möglicherweise nachdem ich zuerst alle Submodule durchlaufen und diese von Remote aktualisiert / abgerufen habe.
Dies ist, wie bereits erwähnt, erledigt
git submodule foreach git pull origin BRANCH
git submodule update
Szenario 2, das meiner Meinung nach das Ziel von OP ist
In einem oder mehreren Submodulen sind neue Dinge passiert, und ich möchte 1) diese Änderungen übernehmen und 2) das übergeordnete Repository so aktualisieren, dass es auf das (neueste) HEAD-Commit dieses / dieser Submodule verweist.
Dies würde von erledigt werden
git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH
Nicht sehr praktisch, da Sie n Pfade zu allen n Submodulen in z. B. einem Skript fest codieren müssten, um die Festschreibungszeiger des übergeordneten Repositorys zu aktualisieren.
Es wäre cool, eine automatisierte Iteration durch jedes Submodul zu haben und den übergeordneten Repository-Zeiger (mit git add
) zu aktualisieren , um auf den Kopf des Submoduls (der Submodule) zu zeigen.
Dafür habe ich dieses kleine Bash-Skript erstellt:
git-update-submodules.sh
#!/bin/bash
APP_PATH=$1
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=$1
shift
if [ -z $BRANCH ]; then
echo "Missing 2nd argument (branch name)";
exit 1;
fi
echo "Working in: $APP_PATH"
cd $APP_PATH
git checkout $BRANCH && git pull --ff origin $BRANCH
git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH
Führen Sie es aus, um es auszuführen
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Ausarbeitung
Zunächst gehe ich davon aus, dass der Zweig mit dem Namen $ BRANCH (zweites Argument) in allen Repositorys vorhanden ist. Fühlen Sie sich frei, dies noch komplexer zu machen.
In den ersten Abschnitten wird überprüft, ob die Argumente vorhanden sind. Dann ziehe ich die neuesten Inhalte des übergeordneten Repositorys ab (ich bevorzuge es, --ff (Schnellvorlauf) zu verwenden, wenn ich nur Pulls mache. Ich habe Rebase Off, BTW).
git checkout $BRANCH && git pull --ff origin $BRANCH
Dann kann eine Submodulinitialisierung erforderlich sein, wenn neue Submodule hinzugefügt wurden oder noch nicht initialisiert wurden:
git submodule sync
git submodule init
git submodule update
Dann aktualisiere / ziehe ich alle Submodule:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Beachten Sie einige Dinge: Zunächst verkette ich einige Git-Befehle mit &&
- was bedeutet, dass der vorherige Befehl fehlerfrei ausgeführt werden muss.
Nach einem möglichen erfolgreichen Pull (wenn neue Inhalte auf der Fernbedienung gefunden wurden) mache ich einen Push, um sicherzustellen, dass ein mögliches Merge-Commit nicht auf dem Client zurückbleibt. Wiederum passiert es nur, wenn ein Zug tatsächlich neue Sachen einbringt.
Schließlich stellt das Finale || true
sicher, dass das Skript bei Fehlern fortgesetzt wird. Damit dies funktioniert, muss alles in der Iteration in doppelte Anführungszeichen gesetzt werden, und die Git-Befehle werden in Klammern gesetzt (Operatorpriorität).
Mein Lieblingsabschnitt:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Iterieren Sie alle Submodule - mit --quiet
, wodurch die Ausgabe 'Eingabe von MODULE_PATH' entfernt wird. Mit 'echo $path'
(muss in einfachen Anführungszeichen stehen) wird der Pfad zum Submodul in die Ausgabe geschrieben.
Diese Liste der relativen Submodulpfade wird in einem Array ( $(...)
) erfasst. Wiederholen Sie dies schließlich git add $i
, um das übergeordnete Repository zu aktualisieren.
Schließlich ein Commit mit einer Meldung, die erklärt, dass das übergeordnete Repository aktualisiert wurde. Dieses Festschreiben wird standardmäßig ignoriert, wenn nichts unternommen wurde. Schieben Sie dies zum Ursprung, und Sie sind fertig.
Ich habe ein Skript, das dies in einem Jenkins- Job ausführt, das anschließend mit einer geplanten automatisierten Bereitstellung verknüpft wird, und es funktioniert wie ein Zauber.
Ich hoffe, das wird jemandem helfen.
--remote
Option die Funktionalität verfügt, die Sie benötigen , wäre es vielleicht nützlich, dies als akzeptierte Antwort und nicht als "von Hand" -Ansatz in Jasons Antwort zu markieren.