Es scheint, als würden in dieser Diskussion zwei verschiedene Szenarien miteinander vermischt:
Szenario 1
Mit den Zeigern meines übergeordneten Repositorys auf die Submodule möchte ich die Übergabe in jedem Submodul, auf das das übergeordnete Repository zeigt, überprüfen, möglicherweise nachdem ich zuerst alle Submodule durchlaufen und diese aus der Ferne aktualisiert/abgerufen habe.
Dies geschieht, wie bereits erwähnt, mit
git submodule foreach git pull origin BRANCH
git submodule update
Szenario 2, auf das OP meiner Meinung nach abzielt
In einem oder mehreren Untermodulen hat sich etwas getan, und ich möchte 1) diese Änderungen übernehmen und 2) das übergeordnete Repository aktualisieren, damit es auf den (neuesten) HEAD-Commit dieses/r Untermodule verweist.
Dies würde geschehen durch
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
Das ist nicht sehr praktisch, da man n Pfade zu allen n Untermodulen in einem Skript zur Aktualisierung der Commit-Pointer des übergeordneten Repositorys fest einprogrammieren müsste.
Es wäre toll, wenn man jedes Submodul automatisch durchlaufen könnte, um den Zeiger des übergeordneten Repositorys zu aktualisieren (mit git add
) auf den Kopf des/der Submodule(s) verweisen.
Zu diesem Zweck 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
Um es auszuführen, führen Sie
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
Ausarbeitung
Zunächst einmal gehe ich davon aus, dass der Zweig mit dem Namen $BRANCH (zweites Argument) in allen Repositories existiert. Sie können dies gerne noch komplexer gestalten.
In den ersten beiden Abschnitten wird überprüft, ob die Argumente vorhanden sind. Dann ziehe ich das neueste Material des übergeordneten Repositorys (ich bevorzuge --ff (fast-forwarding), wenn ich nur pulls mache. Ich habe übrigens rebase ausgeschaltet).
git checkout $BRANCH && git pull --ff origin $BRANCH
Dann kann es notwendig sein, einige Submodule zu initialisieren, wenn neue Submodule hinzugefügt wurden oder noch nicht initialisiert sind:
git submodule sync
git submodule init
git submodule update
Dann aktualisiere/entferne ich alle Untermodule:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
Beachten Sie ein paar Dinge: Zunächst einmal kette ich einige Git-Befehle mit &&
- was bedeutet, dass der vorherige Befehl ohne Fehler ausgeführt werden muss.
Nach einem möglicherweise erfolgreichen Pull (wenn auf der Gegenseite neue Dinge gefunden wurden), mache ich einen Push, um sicherzustellen, dass ein möglicher Merge-Commit nicht auf dem Client zurückbleibt. Wiederum geschieht dies nur wenn ein Pull hat tatsächlich neue Sachen eingebracht.
Schließlich ist die letzte || true
stellt 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 (Vorrang der Operatoren).
Mein Lieblingsteil:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
Iterieren Sie alle Untermodule - mit --quiet
, wodurch die Ausgabe 'Entering MODULE_PATH' entfernt wird. Verwendung von '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 ( $(...)
) - schließlich wiederholen Sie dies und machen git add $i
um das übergeordnete Repository zu aktualisieren.
Schließlich ein Commit mit einer Nachricht, die erklärt, dass das übergeordnete Repository aktualisiert wurde. Dieser Commit wird standardmäßig ignoriert, wenn nichts getan wurde. Schieben Sie dies zum Ursprung und Sie sind fertig.
Ich habe ein Skript, das dies in einer Jenkins Job, der anschließend an eine geplante automatische Bereitstellung gekoppelt ist, und es funktioniert wunderbar.
Ich hoffe, dass dies jemandem helfen wird.