Git-Workflow¶
Diese Seite erklärt, wie wir mit Git arbeiten und wie Änderungen aus dem Repo auf die Server kommen. Die Befehle dazu stehen in den Anleitungen, die unten verlinkt sind.
Git, so weit wir es brauchen¶
Git verwaltet Dateien zusammen mit ihrer Änderungsgeschichte. Unser Repo liegt zentral auf Codeberg, und alle, die an der Infrastruktur arbeiten, haben eine Kopie davon auf ihrem Rechner.
Für unsere Arbeit reichen wenige Begriffe:
- Ein Commit speichert einen Stand von Änderungen, zusammen mit einer Beschreibung, wer ihn gemacht hat und wann.
- Mit Push lädt man die eigenen Commits nach Codeberg hoch, mit Pull holt man die Commits der anderen.
mainist der Hauptzweig des Repos, auf dem wir alle arbeiten.
Alle Commits zusammen sind die Historie des Repos. Sie ist unser Änderungsprotokoll: Für jede Zeile Konfiguration lässt sich nachsehen, wer sie wann geändert hat und warum.
Das Repo ist die Wahrheit: Was auf den Servern laufen soll, steht im Repo, und jede Änderung geht zuerst dorthin. Dieser Grundgedanke heißt GitOps.
Mehr über Git selbst steht im Git-Buch, Kapitel 1 bis 3 reichen für unsere Arbeit.
Ausrollen¶
Ausgerollt wird von deinem eigenen Rechner aus.
cue cmd apply überträgt die Konfiguration per SSH auf den jeweiligen Host, desync und terraform apply sprechen direkt mit der Schnittstelle (API) von deSEC bzw. Authentik.
Es gibt keinen Dienst, der nach einem Push automatisch ausrollt. Ein Push allein ändert also nichts auf den Servern; ausrollen und pushen sind zwei getrennte Schritte, und beide sind nötig.
Der ganze Ablauf vom Pull bis zum Push steht in der Anleitung Änderung ausrollen.
Direkt auf main¶
Jede Änderung wird direkt auf main committet; einen Pull Request, den jemand anders erst prüft, gibt es nur, wenn man ausdrücklich eine zweite Meinung möchte.
Ein Pull Request lohnt sich, wenn regelmäßig jemand Zeit für das Prüfen hat. In unserem Team von weniger als fünf Leuten würden Änderungen dann oft tagelang liegen bleiben, und dringende Korrekturen müssten warten. Stattdessen sorgen gute Commit-Messages dafür, dass jede Änderung im Nachhinein nachvollziehbar ist (siehe Gute Commit-Messages ersetzen das Review).
Vor jeder Änderung pullen und plan ausführen¶
Vor jeder Änderung holst du mit git pull --rebase den neuesten Stand und führst dann plan aus, noch bevor du selbst etwas änderst.
Dabei darf plan keine Unterschiede zeigen.
Ausgerollt wird immer das, was auf deinem Rechner im Repo steht. Hast du die Commits der anderen noch nicht geholt, fehlen ihre Änderungen in deinem Sollzustand, und dein apply macht sie auf dem Server rückgängig.
sequenceDiagram
participant A as Anna
participant R as Repo auf Codeberg
participant S as Server
participant B as Ben
B->>R: pull (Stand 1)
A->>R: pull (Stand 1)
A->>S: apply: neue HedgeDoc-Version
A->>R: commit und push (Stand 2)
Note over B: hat Stand 2 nicht geholt
B->>S: apply mit Stand 1 + eigener Änderung
Note over S: HedgeDoc wieder auf alter Version
Der Pull allein reicht aber nicht. Hat jemand ausgerollt und noch nicht gepusht oder etwas von Hand auf dem Server geändert, stimmt auch der neueste Stand im Repo nicht mit dem Server überein.
Zeigt plan nach dem Pull keine Unterschiede, passen Repo und Server zusammen, und alles, was plan später zeigt, stammt von deiner eigenen Änderung. Zeigt plan schon vorher Unterschiede, klärst du zuerst, woher sie kommen. Sonst vermischen sie sich mit deiner Änderung, und dein apply rollt etwas aus oder macht etwas rückgängig, von dem du nichts weißt. Was in so einem Fall zu tun ist, steht in plan zeigt unerwartete Änderungen.
Erst ausrollen, dann committen und sofort pushen¶
Eine Änderung rollst du zuerst mit apply aus; erst wenn sie funktioniert, committest du sie und pushst sofort.
Ausgerollt wird vor dem Commit, weil apply erst zeigt, ob die Änderung wirklich funktioniert. Schlägt sie fehl, korrigiert man sie, bevor sie in die gemeinsame Historie kommt.
Gepusht wird sofort, weil das Repo nur dann mit den Servern übereinstimmt, wenn jede ausgerollte Änderung auch in Codeberg ankommt. Wer ausrollt und nicht pusht, hinterlässt einen Server, dessen Stand nirgends im Repo steht; das nächste apply von jemand anderem macht die Änderung wieder rückgängig.
Rebase statt Merge¶
Haben zwei Leute gleichzeitig committet, muss Git die beiden Stände zusammenführen. Wir lassen Git dabei einen Rebase machen: Die eigenen, noch nicht gepushten Commits werden hinter die Commits der anderen gehängt. Dadurch bleibt die Historie eine gerade Linie, und man kann sie von oben nach unten lesen wie ein Protokoll.
Ohne diese Einstellung führt git pull die Stände per Merge zusammen und legt dafür jedes Mal einen eigenen Merge-Commit an.
Der enthält keine eigene Änderung, nur die Zusammenführung, und heißt meist nichtssagend „Merge branch 'main' of …“.
Weil wir viele kleine Änderungen direkt auf main machen, stünde so neben fast jedem echten Commit ein Merge-Commit, und die Historie würde sich ständig verzweigen und wieder zusammenlaufen.
Wer später nachvollziehen will, was wann geändert wurde, müsste sich durch diese Verzweigungen arbeiten.
Damit git pull immer so arbeitet, setzen wir in Git die Einstellung pull.rebase; das gehört zu Arbeitsrechner einrichten.
Einen Konflikt beim Rebase gibt es nur, wenn zwei Leute gleichzeitig dieselben Zeilen geändert haben.
In der Praxis kommt das so gut wie nie vor: Wir ändern selten etwas, arbeiten kaum je gleichzeitig am Repo, und wenn doch, sprechen wir uns vorher in Signal ab.
Weil jede Änderung mit einem Pull beginnt und mit einem sofortigen Push endet, ist der eigene Stand außerdem fast immer aktuell.
Falls es doch einmal passiert, hilft Git-Konflikt lösen.
Gute Commit-Messages ersetzen das Review¶
Weil niemand eine Änderung vorher prüft, muss die Commit-Message später alles erklären. Sie sagt in der ersten Zeile kurz, was geändert wurde, und in den Zeilen darunter, warum, wenn das nicht offensichtlich ist.
Zwei Beispiele aus unserer Historie:
fix discourse reverse proxy config, darunter: „this allows to use the actual client ip in logs, admin ui, etc“. Die erste Zeile sagt, was geändert wurde, die zweite, welches Problem damit gelöst ist.update nextcloud to 20260825_084538, darunter der Hinweis, dass auch die Konfiguration angepasst wurde, mit Link auf die Änderungen beim Hersteller. Wer später wissen will, woher die geänderten Einstellungen kommen, findet die Quelle direkt im Commit.
Eine Message wie „update“ oder „fix“ sagt dagegen nichts: Man muss erst den Inhalt des Commits lesen, um zu erraten, worum es ging.
Weiterlesen¶
- Änderung ausrollen
- Git-Konflikt lösen
- plan zeigt unerwartete Änderungen
- Infrastructure as Code: was plan und apply tun
- Git-Buch für alles Allgemeine zu Git