Dieses Dokument beschreibt den Git-Workflow für unsere Repositories
supplierRatingBackend und supplierRatingFrontend. Die Einhaltung dieses
Workflows ist für alle Teammitglieder verpflichtend, um Code-Qualität,
Nachvollziehbarkeit und einen stabilen main-Branch sicherzustellen.
Unser Modell basiert auf dem GitHub Flow, einem schlanken und modernen
Ansatz. Das Kernprinzip ist ein stabiler main-Branch, von dem alle
Arbeiten in kurzlebigen "Topic Branches" abgezweigt werden. Dieser Workflow
ist bewusst einfach gehalten und eine klare Alternative zu komplexeren Modellen
wie dem Gitflow.
Ziele dieses Dokuments:
- Stabilität: Der
main-Branch ist immer stabil, kompilierbar und potenziell auslieferbar. - Qualitätssicherung: Kein Code wird ohne ein "Vier-Augen-Prinzip" (Code
Review) in den
main-Branch integriert. - Parallelisierung: Alle Teammitglieder können parallel an verschiedenen Funktionen arbeiten, ohne sich gegenseitig zu blockieren.
- Nachvollziehbarkeit: Die Git-Historie ist sauber und lesbar.
Der Workflow-Kodex:
- Pushe niemals direkt auf den
main-Branch. - Zweige immer vom aktuellsten
main-Branch ab (git pull origin main, bevor du einen neuen Branch erstellst). - Jeder Merge in
mainerfordert einen Pull Request (PR). - Jeder PR erfordert mindestens ein "Approval" von einem anderen Teammitglied (der Autor darf nicht selbst approven).
- Mache kleine, logische Commits
- Nach dem Merge wird der Arbeits-Branch gelöscht
Dies ist der Standard-Ablauf für jede neue Aufgabe (Feature, Bugfix, etc.). Für detailliertere Beschreibung der einzelnen Schritte, siehe weiter unten.
-
Synchronisieren: Hole den neuesten Stand von GitHub.
git checkout main git pull origin main
-
Abzweigen: Erstelle deinen eigenen Arbeits-Branch.
git checkout -b feature/supplier-list-component
-
Arbeiten: Programmiere und erstelle lokale, saubere Commits.
git add <meine-datei.java> git commit -m "feat: Add xyz"
-
Pushen: Schiebe deinen fertigen Branch auf GitHub.
git push -u origin feature/supplier-list-component
-
Pull Request (PR) erstellen: Gehe auf GitHub und erstelle einen PR für deinen Branch, um sie in
mainzu mergen. Weise deine Teamkollegen als Reviewer zu. -
Review & Mergen: Warte auf das "Approval" (den grünen Haken) von mindestens einem Kollegen. Klicke dann auf "Squash and Merge" auf GitHub und lösche anschliessend deinen Branch.
-
Aufräumen: Räume deine lokale Code-Basis auf und bringe sie auf den neusten Stand.
git checkout main git pull origin main git branch -D feature/supplier-list-component
Dies ist der tägliche Prozess für jedes Teammitglied, das eine neue Aufgabe beginnt:
Wähle den passenden Präfix (siehe unten).
# Beispiel für eine neue Funktion
git checkout -b feature/supplier-list-componentJetzt programmierst du. Erstelle kleine, logische Commits gemäss unserer Commit-Message-Richtlinie (siehe unten).
Bevorzuge das gezielte Hinzufügen von Dateien (git add <file>) statt dem
pauschalen git add ., um saubere, atomare Commits zu erstellen.
# Beispielhafter Arbeitszyklus (z.B. im Frontend-Repo)
# Füge nur die Datei für die neue Komponente hinzu
git add src/app/components/supplier-list/supplier-list.component.ts
git commit -m "feat: Add basic component structure for supplier list"
# ... weiter programmieren (z.B. am Styling) ...
# Füge nur die geänderte CSS-Datei hinzu
git add src/app/components/supplier-list/supplier-list.component.css
git commit -m "style: Adjust CSS grid for supplier list"
# Profi-Tipp: Mit `git add -p` kannst du sogar einzelne Code-Blöcke
# innerhalb einer einzigen Datei separat hinzufügen.Manchmal hast du zwei logisch getrennte Dinge in derselben Datei geändert
(z.B. ein Feature hinzugefügt UND einen Tippfehler korrigiert). Mit git add -p
kannst du die Datei "Stück für Stück" (Hunk für Hunk) zum Commit hinzufügen.
Szenario: Du hast in supplier-list.component.ts eine neue Funktion
(getSuppliers) hinzugefügt (feat) und in derselben Datei die Einrückung im
Konstruktor korrigiert (style). Du willst dies in zwei separaten Commits
festhalten.
-
Du tippst:
git add -p src/app/components/supplier-list/supplier-list.component.ts -
Git zeigt dir den ersten Block (den "Hunk") – die Einrückung:
diff --git a/src/app/components/supplier-list/supplier-list.component.ts b/src/app/components/supplier-list/supplier-list.component.ts --- a/src/app/components/supplier-list/supplier-list.component.ts +++ b/src/app/components/supplier-list/supplier-list.component.ts @@ -10,7 +10,7 @@ ) { - this.pageTitle = 'Suppliers'; // SCHLECHTE EINRÜCKUNG + this.pageTitle = 'Suppliers'; // KORRIGIERTE EINRÜCKUNG }
Stage this hunk [y,n,q,a,d,s,e,?]? -
Du willst dies nicht im
feat-Commit haben. Du tippst: n (für "No"). -
Git zeigt dir den zweiten Block – die neue Funktion:
@@ -20,6 +20,11 @@ // ... alter Code ... } + getSuppliers(): void { + // ... neue coole Logik ... + } +}
Stage this hunk [y,n,q,a,d,s,e,?]? -
Das ist dein Feature. Du tippst: y (für "Yes").
-
Jetzt machst du deinen ersten Commit (nur mit der neuen Funktion):
git commit -m "feat: Add getSuppliers method" -
Anschliessend fügst du die übrig gebliebene Änderung (die Einrückung) hinzu und committest sie separat:
git add src/app/components/supplier-list/supplier-list.component.tsgit commit -m "style: Fix indentation in constructor"
Du hast nun eine perfekt saubere Git-Historie, obwohl beide Änderungen in derselben Datei waren.
-
Gehe auf GitHub. Du wirst einen gelben Banner sehen, der dir anbietet, einen PR zu erstellen.
-
Titel: Gib einen klaren Titel (z.B.
Feature: Supplier List Component). -
Beschreibung: Fülle die Beschreibung aus. Was macht dieser Code? Wie kann man ihn testen?
-
Reviewers: Weise die anderen beiden Teammitglieder als Reviewer zu.
- Review (Die Anderen): Die Reviewer schauen sich den Code an ("Files Changed").
- Diskutieren & Anpassen (Du): Du reagierst auf Kommentare und pusht ggf. neue Commits auf deinen Branch. Der PR aktualisiert sich automatisch.
- Approval (Die Anderen): Wenn alles passt, gibt mindestens ein Reviewer ein "Approval".
- Mergen (Du): Sobald du das "Approval" hast, klickst du auf den "Squash
and Merge"-Button.
- Warum "Squash and Merge"? Dies fasst alle deine (vielleicht 10 kleinen)
Commits aus dem Arbeits-Branch zu einem einzigen, sauberen Commit im
main-Branch zusammen. Das hält diemain-Historie extrem sauber. - GitHub wird fragen, ob der Branch gelöscht werden soll. Ja, das soll er.
- Warum "Squash and Merge"? Dies fasst alle deine (vielleicht 10 kleinen)
Commits aus dem Arbeits-Branch zu einem einzigen, sauberen Commit im
Sobald dein Pull Request in main gemerged und der Feature-Branch auf GitHub
gelöscht wurde (Schritt 6), ist deine lokale Maschine noch nicht auf dem
neuesten Stand.
Führe immer diese drei Schritte aus, um deinen Arbeitsplatz sauber zu halten und für die nächste Aufgabe vorzubereiten:
-
Zum
main-Branch wechselnWechsle zurück auf den Haupt-Branch.
git checkout main
-
mainsynchronisieren (und aufräumen)Hole dir die neuesten Änderungen von
main(inklusive deines Commits, der gerade gemerged wurde).git pull origin main
Falls du global
fetch.prunekonfiguriert hast: Wenn dugit config --global fetch.prune truegesetzt hast, wird bei diesempullautomatisch einfetch --pruneausgeführt. Git bemerkt, dassorigin/feature/supplier-list-componentauf GitHub gelöscht wurde, und löscht diesen "Tracking-Pointer" lokal.Falls du
fetch.prunenicht global konfiguriert hast: Wenn dufetch.prune truenicht gesetzt hast, müsstest du hier manuell den lokalen "Tracking-Pointer" löschen:git fetch --prune
-
Alte lokale Branch löschen
Dein lokales Repo ist jetzt sauber, aber der lokale Branch
feature/supplier-list-componentexistiert noch. Da er nun sicher inmaingemerged ist, wird er nicht mehr gebraucht.Da wir in Schritt 6 "Squash and Merge" verwenden, sind die ursprünglichen Commits unseres Arbeits-Branches technisch gesehen nicht mehr Teil von
main. Git würde sich daher bei einem normalen-d(sicheres Löschen) beschweren.Wir müssen Git daher anweisen, das Löschen zu erzwingen (
-D), da wir wissen, dass die Arbeit auf GitHub korrekt integriert wurde:git branch -D feature/supplier-list-component
Jetzt ist dein lokales Repo sauber,
mainist aktuell, und du bist bereit für Schritt 1 des nächsten Features.
Wenn dein PR nicht automatisch gemerged werden kann (weil main sich in der
Zwischenzeit geändert hat), musst du den Konflikt in deinem Arbeits-Branch
lösen.
-
Hole dir dazu zunächst die neuesten Änderungen von
main:git checkout feature/supplier-list-component git pull origin main
-
Git wird nun versuchen, die
main-Änderungen in deinen Branch zu integrieren. Wenn es Konflikte gibt, meldet Git dies (z.B.CONFLICT (content): Merge conflict in ...). Die Datei ist jetzt in einem speziellen "konfliktbehafteten" Zustand. -
Öffne die konfliktreichen Dateien in IntelliJ/WebStorm/Neovim.
3a. Was du siehst: Die Konflikt-Marker
Git hat die Datei an den problematischen Stellen bearbeitet und spezielle Marker eingefügt, um dir beide Versionen des Codes zu zeigen:
<<<<<<< HEAD (Deine Änderungen) // Dein Code von deinem Branch 'feature/supplier-list-component' // z.B. eine Zeile, die du hinzugefügt hast System.out.println("Hallo Welt!"); ======= // Der "neue" Code von der 'main'-Branch // z.B. eine andere Zeile, die ein Kollege an derselben Stelle hinzugefügt hat System.out.println("Guten Tag!"); >>>>>>> main
<<<<<<< HEAD: Dies markiert den Anfang deiner Änderungen (die Version auf deinem aktuellen Branchfeature/supplier-list-component).=======: Dies ist der Trennblock zwischen den beiden Versionen.>>>>>>> main: Dies markiert das Ende der eingehenden Änderungen (die Version vommain-Branch, den du gerade gepullt hast).
3b. Deine Aufgabe: Die Auflösung
Deine Aufgabe ist es, diese Blöcke (inklusive der Marker-Zeilen
<<<,===,>>>!) komplett zu entfernen und sie durch den endgültigen, korrekten Code zu ersetzen.Du musst eine fachliche Entscheidung treffen:
- Behältst du deinen Code? Dann lösche die
main-Version und alle Marker. - Behältst du den
main-Code? Dann lösche deine Version und alle Marker. - Kombinierst du beides? (z.B. wenn beide eine Zeile zu einer Liste hinzugefügt haben). Dann nimmst du beide Code-Teile, ordnest sie korrekt an und löschst alle Marker.
Das Wichtigste ist: Am Ende muss die Datei wieder gültigen Code enthalten, so als ob der Konflikt nie passiert wäre.
Nutze den Merge-Editor deiner IDE
Du musst das fast nie von Hand (im reinen Texteditor) machen. IntelliJ / WebStorm / und z.T. Neovim erkennen den Konflikt und markieren die Datei rot.
- Klicke mit der rechten Maustaste auf die Datei und wähle
Git->Resolve Conflicts.... - Die IDE öffnet einen speziellen 3-Wege-Merge-Editor.
- Dieser zeigt dir drei Spalten:
- Links: Deine Version (
HEAD) - Rechts: Die
main-Version (Eingehend) - Mitte: Das Endergebnis (Das ist, was du bearbeitest)
- Links: Deine Version (
- Du kannst jetzt mit kleinen Pfeil-Buttons (
>>oder<<) auswählen, welche Zeilen du aus welcher Version in die mittlere Spalte (das Endergebnis) übernehmen möchtest. Du kannst in der Mitte auch direkt tippen, um beide Versionen zu kombinieren. - Wenn du fertig bist, klickst du auf "Apply" oder "Resolve". Die IDE speichert dann die Datei in der finalen Version (die mittlere Spalte) ohne die Konflikt-Marker.
-
Wenn alle Konflikte in allen Dateien gelöst sind, markierst du die Dateien als gelöst (das macht die IDE oft automatisch, wenn du den Merge-Editor schliesst).
Du führst dann
git addaus, um die "reparierten" Dateien zu stagen, gefolgt vongit commit, um den Merge-Vorgang abzuschliessen. Die Commit-Message wird oft von Git vor-ausgefüllt.# Füge die nun korrigierten Dateien hinzu git add . # Schliesse den Merge-Commit ab # (oft öffnet sich ein Editor mit einer vor-ausgefüllten Message wie "Merge branch 'main' into ...") # Alternativ: git commit -m "fix: Merge conflicts from main"
-
Pushe deinen Branch erneut. Dein lokaler Branch enthält jetzt deine Änderungen UND die neuen Änderungen von
mainUND deinen "Reparatur-Commit". Der PR auf GitHub sollte jetzt "clean" sein und gemerged werden können.git push
Manchmal stellt man während der Arbeit an einem Branch (z.B.
feature/falsche-idee) fest, dass der gesamte Ansatz falsch war oder die
Funktion doch nicht benötigt wird. Du willst alle Commits auf diesem Branch
verwerfen und sauber zu main zurückkehren.
Wichtig: Dieser Prozess löscht die Arbeit auf diesem Branch unwiderruflich.
Falls du im Arbeitsverzeichnis noch ungespeicherte, nicht-committete
Änderungen hast, die du vielleicht für einen anderen Branch brauchst, sichere
sie mit git stash.
(Siehe den nächsten Abschnitt Sonderfall:git stash`` für Details, wie man
alle oder auch nur einzelne Dateien sichert).
git checkout mainFalls du den Branch schon einmal auf GitHub gepusht hast (Schritt 4 des
Standard-Workflows), musst du ihn zuerst auf dem Remote-Server (origin)
löschen.
# Syntax: git push <remote> --delete <branch-name>
git push origin --delete feature/falsche-idee(Wenn der Branch nie gepusht wurde, schlägt dieser Befehl einfach fehl, das ist unbedenklich.)
Da dieser Branch per Definition nicht in main gemerged wurde, musst
du das Löschen mit -D (grosses D) erzwingen.
git branch -D feature/falsche-ideeDu bist jetzt wieder sauber auf main und der "falsche" Branch ist
sowohl lokal als auch remote (falls er dort war) gelöscht.
Stell dir den git stash als ein "Handschuhfach" oder einen Stapel (Stack)
für unfertige Arbeit vor. Es ist kein Branch, sondern ein separater,
lokaler Speicherort (nur in deinem Repo, wird nie gepusht), um
nicht-committete Änderungen schnell beiseitezulegen.
Der Hauptzweck ist, dein Arbeitsverzeichnis (Working Directory) schnell
sauber zu bekommen (z.B. weil du dringend auf main wechseln musst, um einen
Bugfix zu starten), ohne die aktuelle Arbeit committen zu müssen.
| Befehl | Erklärung |
|---|---|
git stash |
Alles sichern: Nimmt alle geänderten und gestageten Dateien (die Git bereits kennt) und legt sie in den Stash. Dein Arbeitsverzeichnis ist danach sauber (wie nach einem git commit). |
git stash push -m "Nachricht" |
Sichern mit Nachricht: Wie git stash, aber fügt eine beschreibende Nachricht hinzu (sehr nützlich, wenn man mehrere Dinge stasht). |
git stash -u |
Inklusive neuer Dateien: Sichert auch alle untracked (neuen) Dateien. |
git stash -p |
Interaktiv sichern: (Patch-Modus) Geht interaktiv durch alle "Hunks" (Code-Blöcke) und fragt dich, ob du diesen Teil stashen möchtest ([y,n,q,...]). Identisch zu git add -p. |
git stash push <dateiname> |
Nur bestimmte Dateien sichern: Sichert nur die Änderungen an den angegebenen Dateien. |
| Befehl | Erklärung |
|---|---|
git stash list |
Stash-Liste anzeigen: Zeigt alle "Pakete" an, die im Stash liegen, mit ihrer ID (z.B. stash@{0}) und der Nachricht. |
git stash show stash@{1} |
Inhalt ansehen: Zeigt an, welche Dateien in einem bestimmten Stash-Eintrag geändert wurden (z.B. stash@{1}). |
git stash show -p stash@{0} |
Änderungen im Detail ansehen: Zeigt den vollen diff (den Code) des Stash-Eintrags an. |
Das Holen von Änderungen ist nicht an einen Branch gebunden. Du kannst
auf feature/A etwas stashen, zu feature/B wechseln und es dort wieder
herausholen.
| Befehl | Erklärung |
|---|---|
git stash pop |
Holen & Löschen (Standard): Nimmt den obersten Eintrag (stash@{0}), wendet ihn auf dein aktuelles Arbeitsverzeichnis an und löscht ihn vom Stash-Stapel. |
git stash apply |
Holen & Behalten: Wendet den obersten Eintrag an, behält ihn aber auf dem Stash-Stapel (nützlich, wenn du dieselbe Änderung auf mehreren Branches anwenden willst). |
git stash pop stash@{2} |
Spezifisches Holen & Löschen: Wendet einen bestimmten Eintrag (hier: stash@{2}) an und löscht ihn. |
| Befehl | Erklärung |
|---|---|
git stash drop stash@{1} |
Spezifisches Löschen: Löscht den Eintrag stash@{1} unwiderruflich, ohne ihn anzuwenden. |
git stash clear |
Alles Löschen: Löscht alle Einträge im Stash unwiderruflich. |
Persistenz: Stash-Einträge bleiben so lange in deinem lokalen Repo, bis du
sie mit pop, drop oder clear explizit löschst. Sie überleben
Reboots, Branch-Wechsel und Commits.
Git ist ein verteiltes Versionskontrollsystem (VCS).
Versionierung: Git speichert "Schnappschüsse" (Snapshots) des gesamten Projekts bei jeder Änderung (einem "Commit"). Man kann jederzeit zu jedem beliebigen Schnappschuss in der Vergangenheit zurückkehren.
-
Verteilt: Jeder Entwickler hat eine vollständige, lokale Kopie des gesamten Projektverlaufs (aller Versionen) auf seinem eigenen Rechner. Dies ermöglicht Commits zu erstellen, Branches wechseln und die Historie einsehen, ohne online zu sein.
GitHub ist nicht Git. GitHub ist eine Cloud-Hosting-Plattform für Git-Repositories (Projekte).
Git ist das Werkzeug, GitHub ist der zentrale Ort, an dem wir unseren Code (das
origin-Repo) ablegen. GitHub stellt die Infrastruktur für die Zusammenarbeit
um Git herum bereit, insbesondere für:
-
Zentraler Speicher: Der
origin, mit dem alle ihre lokalen Kopien synchronisieren. -
Code Reviews: Die Pull Requests (PRs), die das Kernstück unseres Workflows sind.
-
Team-Management: Unsere "SupplierRatingSoftware" Organization.
Dies ist ein "Cheat Sheet" der Befehle, die du täglich brauchen wirst.
| Befehl | Erklärung |
|---|---|
| Setup | |
git clone <url> |
Klont ein Remote-Repository (z.B. von GitHub) auf deinen lokalen Rechner. Das machst du einmal pro Repo. |
| Lokaler Workflow | |
git status |
Dein wichtigster Befehl. Zeigt dir an, welche Dateien geändert, welche "gestaged" sind und auf welcher Branch du bist. |
git add <file> |
Fügt eine Datei zur Staging Area hinzu. |
git add -p |
Fügt nur Teile (Hunks) einer Datei zur Staging Area hinzu (sehr mächtig für saubere Commits). |
git commit -m "..." |
Erstellt einen Commit mit allen Änderungen aus der Staging Area. |
git log |
Zeigt die Commit-Historie an. (Drücke q zum Beenden). |
| Branching | |
git branch |
Listet alle deine lokalen Branches auf und zeigt, wo du bist (*). |
git checkout <branch> |
Wechselt zum angegebenen Branch (ändert die Dateien in deinem Arbeitsordner auf den Stand dieses Branch). |
git checkout -b <name> |
Erstellt einen neue Branch vom aktuellen HEAD und wechselt sofort zu ihm. (Unser Standard zum Starten von Arbeit). |
| Zusammenarbeit (Sync) | |
git fetch origin |
Holen: Holt alle neuen Daten (neue Commits, neue Branches) von GitHub (origin), ohne deine lokale Arbeit anzufassen. Es aktualisiert nur Gits "Wissen" darüber, was remote passiert ist. |
git pull origin <branch> |
Ziehen: Macht ein git fetch UND versucht sofort, die Änderungen in deinem aktuell ausgecheckte Branch zu mergen. (Wird in unserem Workflow primär für das Aktualisieren von main genutzt). |
git push origin <branch> |
Schieben: Sendet deine lokalen Commits auf den angegebenen Branch auf GitHub (origin). Dies ist der Moment, in dem deine Arbeit für andere sichtbar wird. |
Dies ist ein "Cheat Sheet" weiterführender Befehle für Sonderfälle.
| Befehl | Erklärung |
|---|---|
| Lokale Änderungen verwalten | |
git restore --staged <file> |
Unstage: Entfernt eine Datei wieder aus der Staging Area (das Gegenteil von git add). |
git restore <file> |
Änderungen verwerfen: Setzt eine Datei auf den Stand des letzten Commits zurück. (Vorsicht, alle nicht-committeten Änderungen an dieser Datei sind weg!) |
git stash |
Änderungen parken: Legt alle deine aktuellen (nicht-committeten) Änderungen "ins Handschuhfach", um sauber den Branch wechseln zu können. |
git stash pop |
Geparktes zurückholen: Holt die zuletzt geparkten Änderungen aus dem Handschuhfach zurück. |
git diff |
Unterschiede anzeigen: Zeigt alle Änderungen im Arbeitsverzeichnis an, die noch nicht gestaged sind. |
git diff --staged |
Unterschiede (Staging) anzeigen: Zeigt alle Änderungen an, die bereits in der Staging Area sind. |
| Lokale Branches verwalten | |
git branch -d <branch> |
Lokalen Branch löschen: Löscht den Branch auf deinem Rechner (sicher, funktioniert nur, wenn sie in main gemerged wurde). |
git branch -D <branch> |
Löschen erzwingen: Löscht einen lokalen Branch, auch wenn er nicht gemerged wurde (mit Vorsicht!). |
git fetch --prune |
Remote-Refs aufräumen: Aktualisiert deine lokale "Sicht" auf origin und löscht alle "Tracking-Branches", die auf GitHub schon gelöscht wurden. |
| Historie & Rollback | |
git checkout <hash> |
Alten Commit ansehen: "Reist" in der Zeit zurück zu einem alten Commit (z.B. git checkout a1b2c3d). Du bist dann im "detached HEAD"-Zustand (nur zum Schauen). |
git checkout <branch> |
Zurück zur Gegenwart: Verlässt den "detached HEAD"-Zustand und kehrt zur Spitze eines Branch zurück (z.B. git checkout main). |
git revert <hash> |
Rollback (Sicher): Deine Rollback-Strategie. Erstellt einen neuen Commit, der die Änderungen eines alten Commits (<hash>) exakt rückgängig macht. |
git reset --hard <hash> |
Rollback (Gefährlich): Setzt den HEAD-Zeiger deiner Branch auf einen alten Commit (<hash>) und löscht alle Commits danach. (NIEMALS auf main verwenden!). |
Diese Befehle werden meist einmal global (--global) gesetzt
oder dienen zur Überprüfung der Konfiguration.
| Befehl | Erklärung |
|---|---|
git config --global user.name "..." |
Autorennamen: Setzt deinen Autorennamen global (erscheint in allen Commits). |
git config --global user.email "..." |
Autoren-E-Mail: Setzt deine Autoren-E-Mail global (muss mit GitHub-Account übereinstimmen). |
git config --global init.defaultBranch main |
Standard-Branch: Stellt sicher, dass neue Repos lokal main als Standard-Branch nutzen. |
git config --global fetch.prune true |
Veraltete Remote-Zeiger: Sorgt dafür, dass git fetch und git pull veraltete Remote-Zeiger löschen. |
git config --global core.editor "..." |
Standard-Texteditor: (Optional) Legt deinen Standard-Texteditor fest (z.B. nvim). |
git config --list |
Konfiguration anzeigen: Listet alle aktuellen Git-Einstellungen auf. |
Mit gh kannst du fast alles, was du auf der GitHub-Webseite machst, direkt im
Terminal erledigen. Der wichtigste Befehl ist gh auth login (siehe Setup).
Hier sind die nützlichsten Befehle für unseren Workflow:
| Befehl | Erklärung |
|---|---|
gh repo clone <org>/<repo> |
Klont ein Repo der Organization (z.B: gh repo clone SupplierRatingSoftware/supplierRatingBackend). |
gh pr create |
Der Wichtigste: Erstellt einen Pull Request von deinem aktuellen Branch. Startet einen interaktiven Prozess für Titel, Body, Reviewer etc. |
gh pr create --web |
Erstellt den PR und öffnet ihn direkt im Browser zur finalen Kontrolle (sehr empfohlen). |
gh pr create -t "Titel" -b "Body" -r <user> |
Erstellt einen PR non-interaktiv mit Titel, Body und Reviewer. |
gh pr list |
Zeigt alle offenen PRs im Repository an. |
gh pr checkout <id> |
Extrem nützlich für Reviews: Lädt den Code eines PRs (anhand seiner ID-Nummer) in einen lokalen Branch, damit du ihn testen kannst. |
gh pr status |
Zeigt dir den Status deiner eigenen PRs und der PRs, die auf dein Review warten. |
gh pr merge <id> |
Merged einen PR (nach Approval) direkt von der CLI aus. (Das "Squash & Merge" im Browser ist aber oft sicherer für unseren Workflow). |
Um den Workflow zu verstehen, müssen wir die folgenden Begriffe kennen.
-
Repository (Repo): Das gesamte Projektverzeichnis, inklusive aller Dateien und der kompletten Git-Historie.
- Remote-Repository: Unsere "Master-Kopie", die auf den Servern von
GitHub liegt. Dies ist der
origin. - Lokales-Repository: Deine persönliche Kopie des gesamten Projekts auf
deinem Laptop, die nach einem
git clonein einem Ordner liegt.
- Remote-Repository: Unsere "Master-Kopie", die auf den Servern von
GitHub liegt. Dies ist der
-
Clone (Klonen): Der einmalige Vorgang (
git clone), bei dem du eine vollständige Kopie eines Remote-Repositorys (von GitHub) herunterlädst, um dein Lokales-Repository zu erstellen. Dieser Befehl richtet auch automatisch die Verbindung zu GitHub alsoriginein. -
Branch: Eine parallele Entwicklungslinie. Ein Branch ist im Grunde nur ein simpler, verschiebbarer Zeiger auf einen bestimmten Commit. Das Erstellen ist extrem schnell und erlaubt es uns, an Features, Fixes und Chores zu arbeiten, ohne den stabilen
main-Branch zu gefährden. -
Checkout: Der Vorgang (
git checkout <branch>), bei dem du zwischen Branches wechselst. Wenn du eine Branch "auscheckst", ändert Git die Dateien in deinem Arbeitsverzeichnis, um dem Stand (dem Schnappschuss) dieses Branches zu entsprechen. -
HEAD: Ein spezieller Zeiger, der Git sagt, "wo du gerade bist".
HEADzeigt fast immer auf den Namen des Branches, den du gerade ausgecheckt hast (z.B.feature/user-login). Wenn du einen neuen Commit machst, bewegt Git den Zeiger dieses Branches (und damit auchHEAD) automatisch auf den neuen Commit. -
Stage / Staging Area (Index): Das "Wartezimmer" für deine Commits. Wenn du eine Datei änderst, ist sie nicht automatisch Teil des nächsten Commits. Du musst sie mit
git addexplizit in die Staging Area verschieben. Nur was in der Staging Area ist, wird beim nächstengit commitgespeichert. -
Stash (Das "Handschuhfach"): Ein separater, lokaler Speicherort (kein Branch), um nicht-committete Änderungen schnell beiseitezulegen (z.B. um schnell den Branch zu wechseln). Die Änderungen können später wiedergeholt (
git stash pop) werden. -
Commit: Ein Schnappschuss deines Projekts. Sobald du
git commitausführst, werden alle Änderungen in der Staging Area genommen und als neue, permanente Version in deiner lokalen Git-Datenbank gespeichert. -
Fetch (Holen): Der Vorgang (
git fetch), bei dem dein lokales Git-Repo bei GitHub (origin) nachfragt: "Gibt es etwas Neues?". Es lädt alle neuen Daten herunter (neue Commits, neue Branches), aber ändert absolut nichts an deinem eigenen Code (deiner "Arbeitskopie"). Deinmainbleibt, wo er ist. Es ist ein reines "Aktualisieren der Information". -
Pull (Ziehen): Eine Kombination aus zwei Befehlen:
git fetch+git merge. Eingit pullholt nicht nur die neuen Daten (wiefetch), sondern versucht auch sofort, diese neuen Änderungen in deine aktuell ausgecheckte Branch zu integrieren (zu mergen). -
Push (Schieben): Der Vorgang (
git push), bei dem du deine lokalen Commits (die GitHub noch nicht kennt) zum Remote-Repository (origin) hochlädst. Dies ist der Moment, in dem deine Arbeit für den Rest des Teams sichtbar wird. -
Merge (Zusammenführen): Der Vorgang, bei dem die Historien von zwei verschiedenen Branches kombiniert werden. Wenn du z.B.
feature/user-loginfertig hast, "mergst" du ihn inmain, um alle Commits des Feature-Branch in die Hauptlinie zu integrieren. Hier können Merge-Konflikte entstehen, falls dieselbe Zeile in beiden Branches geändert wurde. -
Pull Request (PR): Dies ist ein GitHub-Konzept (kein reines Git-Konzept). Ein PR ist ein formaler "Merge-Antrag". Anstatt direkt in
mainzu mergen, sagst du dem Team: "Hallo, ich habefeature/user-loginfertig. Bitte schaut euch meinen Code an (Code Review). -
Squash (Zerdrücken/Zusammenfassen): Dies ist eine spezielle Merge-Option auf GitHub. In unserem Workflow machen wir viele kleine Commits auf einem Feature-Branch (
feat: add button,style: fix padding,fix: typo). Ein "Squash and Merge" fasst all diese 10 Commits zu einem einzigen, sauberen Commit zusammen, bevor dieser in denmain-Branch gemerged wird. Dies hält diemain-Historie extrem sauber. -
Remote-Tracking Branch (Tracking-Zeiger): Ein lokales "Lesezeichen" oder "Zeiger" (Pointer) auf den Stand eines Branch auf dem Remote-Server (
origin). Diese Zeiger heissen z.B.origin/mainoderorigin/feature/user-login. Du kannst sie nicht direkt bearbeiten; sie werden nur durchgit fetchaktualisiert und zeigen dir, "Wo war GitHub, als du das letzte Mal nachgeschaut hast?". -
Prune (Bereinigen): Ein Git-Aufräumbefehl (
git fetch --prune), der dein lokales Repo "sauber" hält. Wenn ein Feature-Branch auf GitHub gelöscht wird (z.B. nach einem Merge), existiert dein lokaler "Remote-Tracking Branch" (origin/feature/user-login) immer noch. Ein "Prune"-Befehl löscht diese veralteten Zeiger, die auf dem Remote-Server nicht mehr existieren. -
origin: Der Standard-Kurzname für das Remote-Repository (also das "Master-Repo" auf GitHub). Wenn du
git push origin maintippst, bedeutet das: "Pushe meine lokalemain-Branch zurmain-Branch auf dem Remote-Server namensorigin."
Bevor du mit dem Projekt startest, muss deine lokale Entwicklungsumgebung einmalig konfiguriert werden.
Stelle sicher, dass git (das Tool selbst) und gh (der offizielle GitHub
Befehlszeilen-Client) auf deinem System installiert sind. gh ist nicht
zwingend notwendig, vereinfacht aber die Authentifizierung und das Erstellen von
Pull Requests enorm.
| Betriebssystem | git Installation |
gh (GitHub CLI) Installation |
|---|---|---|
| Arch Linux | sudo pacman -S git |
sudo pacman -S github-cli |
| Debian/Ubuntu | sudo apt update && sudo apt install git |
sudo apt update && sudo apt install gh |
| macOS | brew install git |
brew install gh |
| Windows | winget install --id Git.Git -e --source winget |
winget install --id GitHub.cli |
Nach der Installation musst du Git einmalig konfigurieren. Diese Einstellungen
werden global (--global) für alle deine Projekte auf diesem Rechner
gespeichert.
# 1. Identität (ESSENZIELL)
# Diese Daten erscheinen in jedem Commit, den du machst.
# WICHTIG: Verwende exakt die E-Mail, die mit deinem GitHub-Account verknüpft
# ist.
git config --global user.name "Dein Vorname Nachname"
git config --global user.email "deine-github-email@adresse.com"
# 2. Standard-Branch-Name
# Stellt sicher, dass neue Repos lokal mit 'main' statt 'master' erstellt
# werden.
git config --global init.defaultBranch main
# 3. Automatisches Aufräumen (Prune)
# Sorgt dafür, dass 'git fetch' und 'git pull' automatisch veraltete
# Tracking-Zeiger löschen.
git config --global fetch.prune true
# 4. (Optional) Standard-Editor
# Definiert deinen bevorzugten Editor für Commit-Messages (z.B. vim, nvim, nano)
# `git config --global core.editor "nvim"`Dein lokales git muss sich bei GitHub authentifizieren, um push und pull
Befehle auf private Repositories (wie unseres) ausführen zu dürfen.
Der moderne Weg (Empfohlen): gh auth login
Früher musste man manuell "Personal Access Tokens" (PATs) auf der GitHub-Webseite erstellen und diese (oft unsicher) in der lokalen Git-Konfiguration speichern.
Der gh Client (den du in Schritt 1.1 installiert hast) macht diesen Prozess
trivial. Er verbindet sich sicher über den Browser (OAuth) mit deinem
GitHub-Account und richtet die Authentifizierung (als sicherer Token im
System-Schlüsselbund) für beides ein: für gh und für git.
Anleitung:
-
Führe im Terminal den Befehl aus:
gh auth login
-
Der Client stellt dir ein paar interaktive Fragen:
What account do you want to log into?->GitHub.com(Enter)What is your preferred protocol for Git operations?->HTTPS(Enter)Authenticate Git with your GitHub credentials?->Yes(Enter)How would you like to authenticate?->Login with a web browser(Enter)
-
ghgibt dir einen Einmal-Code und öffnet deinen Browser (oder fordert dich auf, einen Link zu öffnen). -
Bestätige im Browser die Berechtigungen.
-
Fertig. Dein System ist nun sicher mit GitHub verbunden. Du musst nie wieder ein Passwort oder Token manuell in der CLI eingeben, solange der Token im Schlüsselbund deines Systems gespeichert ist.
Technischer Hintergrund
Der Befehl gh auth login (oder genauer gh auth setup-git)
konfiguriert Git so, dass es gh als Credential Helper (Helfer für
Anmeldeinformationen) verwendet.
Wenn git (z.B. bei git pull) nun ein Passwort für GitHub benötigt,
fragt es nicht mehr den Benutzer, sondern es fragt gh. gh wiederum
holt sich das sichere Token aus dem System-Schlüsselbund (z.B. macOS
Keychain, Windows Credential Manager, Linux Secret Service) und gibt es
an git weiter. Das ist sicher und komfortabel.
Dies sollte für den main-Branch in beiden Repositories eingerichtet werden:
- Gehe zu
Settings>Branches. - Erstelle eine "Branch protection rule" für
main. - Aktiviere folgende Haken:
Require a pull request before merging(Verhindert direkte Pushes aufmain).Require at least 1 approval(Erzwingt das Code Review).- (Optional, aber empfohlen)
Dismiss stale pull request approvals when new commits are pushed.
Note: Diese Einstellung wurde bereits in unseren Repositories vorgenommen.
GitHub Actions ist das eingebaute Automatisierungs-Werkzeug (CI/CD) von GitHub. "CI/CD" steht für "Continuous Integration" (kontinuierliches Bauen und Testen) und "Continuous Delivery" (kontinuierliches Ausliefern).
Für uns bedeutet das: Wir können GitHub anweisen, bei bestimmten Ereignissen
(z.B. "jedes Mal, wenn jemand auf main pusht") automatisch Befehle
auszuführen.
Anwendungsbeispiele für unser Projekt:
- Testen: Jedes Mal, wenn ein PR erstellt wird, könnte eine Action
automatisch alle Tests (z.B.
mvn testim Backend) ausführen und den PR blockieren, wenn die Tests fehlschlagen. - Bauen (Build): Jedes Mal, wenn ein PR in
maingemerged wird, könnte eine Action das Projekt bauen (die.jar-Datei oder die statischen Frontend-Dateien). - Automatisches Releasen: Eine Action könnte den gesamten Release-Prozess (Version erhöhen, Tag erstellen, Release veröffentlichen) automatisieren.
Actions werden durch das Erstellen von YAML-Dateien (Textdateien mit der
Endung .yml) in einem speziellen Verzeichnis innerhalb unseres Repositories
konfiguriert:
.github/workflows/
Wenn wir z.B. eine Datei namens .github/workflows/run-tests.yml erstellen,
würde GitHub diese automatisch erkennen und ausführen.
Beispiel (.github/workflows/run-tests.yml):
# Name des Workflows
name: Run Backend Tests
# Auslöser (Event): Wann soll das passieren?
on:
pull_request: # Bei jedem Pull Request auf...
branches: [main] # ... den main-Branch
# Jobs: Was soll passieren?
jobs:
build:
# Auf welchem Betriebssystem soll der Job laufen?
runs-on: ubuntu-latest
steps:
# Schritt 1: Code auschecken
- uses: actions/checkout@v5
# Schritt 2: Java installieren
- name: Set up JDK 25
uses: actions/setup-java@v5
with:
java-version: "25"
distribution: "temurin"
# Schritt 3: Maven-Tests ausführen
- name: Run Maven Tests
run: mvn test-
Öffentliche Repos: GitHub Actions sind komplett kostenlos.
-
Private Repos (Unser Fall):
- Im kostenlosen Plan (den wir als Organization nutzen) sind 2'000 Minuten pro Monat kostenlos enthalten.
- Diese 2'000 Minuten sind für ein 3-Personen-Studienprojekt fast sicherlich mehr als ausreichend.
- Falls wir den "Team"-Plan (z.B. für Branch Protection) wählen würden, wären dort 3'000 Minuten enthalten.
Hier definieren wir die exakten Namensregeln für unsere Branches und Commits.
Um den Zweck eines Branch sofort zu erkennen, verwenden wir klare Präfixe. Die Liste deckt unsere gängigsten Anwendungsfälle ab:
feature/: Für das Hinzufügen einer neuen, für den Benutzer sichtbaren Funktion.feature/user-login-apifeature/supplier-list-component
fix/: Zur Behebung eines Bugs im Code.fix/login-button-disabled-errorfix/supplier-list-sorting
docs/: Für Ergänzungen oder Änderungen an der Dokumentation (z.B.README.md).docs/update-setup-guidedocs/add-api-endpoints-to-readme
refactor/: Für Code-Überarbeitungen, die weder ein Bugfix noch ein neues Feature sind (z.B. Code "aufräumen").refactor/rename-database-servicerefactor/rename-supplier-class
chore/: Für "Hausmeisterarbeiten", die nichts mit dem eigentlichen Code zu tun haben.chore/initial-project-setup(siehe unten)chore/upgrade-angular-versionchore/add-prettier-config
Um eine saubere und einheitliche Historie zu haben, verwenden wir Conventional Commits.
Jede Commit-Message hat das Format: <typ>: <beschreibung>
Das von uns verwendete Set an Typen ist: feat, fix, docs, style,
refactor, test, chore.
feat(Feature): Eine neue Funktion für den Benutzer.fix(Bugfix): Eine Behebung eines Fehlers.docs(Documentation): Änderungen an der Dokumentation.style(Styling): Code-Formatierung, Semikolons, Einrückung. Keine Code-Logik-Änderung.refactor(Refactoring): Code-Änderung, die weder Bugfix noch Feature ist (z.B. "Aufräumen").test(Tests): Hinzufügen oder Anpassen von Tests.chore(Chore, "Hausarbeit"): Routineaufgaben, Build-Skripte, Tool-Konfiguration. Nichts, was der Benutzer sieht.
| Typ | Beispiel-Commit | Erklärung |
|---|---|---|
feat |
feat: Add supplier search bar to list view |
Ein klares neues Feature wird hinzugefügt. |
feat |
feat: Implement POST /api/v1/suppliers endpoint |
Auch das Erstellen eines API-Endpoints ist ein feat. |
fix |
fix: Prevent app crash when supplier list is empty |
Ein klarer Bug wird behoben. |
fix |
fix: Correct http status code from 404 to 401 on auth failure |
Ein Bug in der API-Logik. |
docs |
docs: Update README with new setup instructions |
Reiner Doku-Change. |
style |
style: Run prettier on all .ts files |
Nur Formatierung, keine Logik geändert. |
style |
style: Fix indentation in pom.xml |
Auch Konfigurationsdateien haben einen Stil. |
refactor |
refactor: Extract supplier-card into new component |
Funktionalität bleibt gleich, aber Code-Struktur ist besser. |
refactor |
refactor: Rename SupplierService to SupplierDataService |
Umbenennung für mehr Klarheit. |
test |
test: Add unit tests for supplier-rating validator |
Ein neuer Test wird geschrieben. |
test |
test: Update test for login component |
Ein bestehender Test wird angepasst. |
chore |
chore: Add .dockerignore file |
Eine Konfigurationsdatei für ein Tool. |
chore |
chore: Upgrade angular from 14 to 15 |
Eine Abhängigkeit aktualisieren. |
chore |
chore: Add initial project structure |
Siehe nächster Abschnitt. |
Ein "Breaking Change" (eine Änderung, die bestehenden Code bricht, z.B. eine
API-Änderung) ist kein eigener Typ, sondern wird auf zwei Arten im Commit
signalisiert. Dies löst immer eine MAJOR-Versionserhöhung aus (z.B.
v1.2.0 -> v2.0.0).
-
Durch einen Footer (Fusszeile): Der Commit-Body wird um einen Block erweitert, der mit
BREAKING CHANGE:beginnt.feat: Change API endpoint for users This commit renames the main user endpoint from /users to /api/v1/users to follow the new API guidelines. BREAKING CHANGE: The `/users` endpoint is now `/api/v1/users`. All clients must update their requests. -
Durch ein
!(Ausrufezeichen) nach dem Typ: Dies ist die schnellere Kurzform, wenn die Betreffzeile ausreicht, um den Bruch zu erklären.feat!: Remove 'username' field from User-API
Beide Methoden sind gültig und werden von automatisierten Tools erkannt.
Bevor wir Features (feat) fixen (fix) oder testen (test) können, muss das
Grundgerüst stehen.
- Repo-Initialisierung: Durch das Erstellen des Repos auf GitHub mit
LICENSE,README.mdund.gitignore, wurde bereits einInitial commiterstellt. - Das Grundgerüst: Das Hinzufügen der grundlegenden Ordnerstruktur (z.B.
das leere SpringBoot-Projekt von
start.spring.iooder das leere Angular-Projekt vonng new) ist kein Feature. Es ist eine "Hausmeistertätigkeit" und somitchore. - Der richtige Workflow:
- Erstelle einen Branch:
git checkout -b chore/initial-project-setup - Füge das Projekt-Grundgerüst hinzu (z.B. den Code von
start.spring.io). - Commite es:
git add .->git commit -m "chore: Add initial SpringBoot project structure" - Pushe diesen Branch und erstelle einen PR.
- Warum? Auch wenn es trivial erscheint, ist es eine gute Übung. Vielleicht hat ein Kollege einen Einwand ("Warum hast du 'Lombok' nicht als Dependency hinzugefügt?"). So wird selbst das Setup diskutierbar.
- Erstelle einen Branch:
- Erstes Feature: Dein nächstes Ticket ist dann vielleicht "Erstelle den
ersten API-Endpoint". Dafür erstellst du einen neuen Branch:
git checkout -b feature/hello-world-endpoint. Dein Commit wäre dann:feat: Add GET /hello endpoint.
Sobald wir einen ersten stabilen Stand (MVP) haben und diesen z.B. dem Auftraggeber übergeben kommt Versionierung ins Spiel. Es ist essenziell, es von Anfang an mitzudenken, da unsere Commit-Typen die Versionierung direkt steuern.
Wir verwenden Semantic Versioning (SemVer): MAJOR.MINOR.PATCH (z.B. 1.2.3)
PATCH(z.B. 1.2.2 -> 1.2.3): Wird erhöht, wenn wir einen Bug beheben.MINOR(z.B. 1.2.3 -> 1.3.0): Wird erhöht, wenn wir ein neues Feature hinzufügen, das abwärtskompatibel ist.MAJOR(z.B. 1.3.0 -> 2.0.0): Wird erhöht, wenn wir eine Änderung machen, die nicht abwärtskompatibel ist (eine "Breaking Change").
- Ein Merge eines
fix:-Commits -> Erhöht PATCH. - Ein Merge eines
feat:-Commits -> Erhöht MINOR.
Start-Version: Wir fangen mit 0.1.0 an, sobald wir die erste präsentable
Version des MVP haben. Alle Versionen unter 1.0.0 gelten per Definition als
"instabil".
Dies ist der Prozess, um eine offizielle, neue Version unserer Software zu
erstellen (z.B. v0.1.0).
Wichtiger Hinweis: Unabhängige Versionierung
Da wir zwei separate Repositories (frontend und backend) haben,
versionieren wir diese unabhängig voneinander. Ein Release-Prozess wird
immer nur innerhalb eines Repositories durchgeführt.
Wenn wir nur einen Bug im Backend beheben, erstellen wir eine neue Backend-Version
(z.B. v0.1.1), während die Frontend-Version (z.B. v0.1.0) unverändert
bleibt.
Wir starten mit v0.1.0 für das jeweilige Repo, sobald dessen MVP-Status
erreicht ist.
Wir schauen uns die Commits an, die seit dem letzten Release in main gemerged
wurden.
- Wurden nur
fix:-Commits gemerged? -> PATCH-Erhöhung (z.B.v0.1.0->v0.1.1) - Wurden (auch)
feat:-Commits gemerged? -> MINOR-Erhöhung (z.B.v0.1.1->v0.2.0) - Gab es einen
BREAKING CHANGE:(oderfeat!)? -> MAJOR-Erhöhung (z.B.v0.2.0->v1.0.0)
Der folgende Prozess muss im Ordner des jeweiligen Repositories ausgeführt werden.
Wir bündeln die Versionsänderung in einem eigenen chore-Branch.
git checkout main
git pull origin main
git checkout -b chore/release-v0.1.0Wir passen die Version nur in der relevanten Datei dieses Repos an.
- Backend:
pom.xml-><version>0.1.0</version> - Frontend:
package.json->"version": "0.1.0"
Wir committen diese Änderung, erstellen einen PR und mergen ihn.
# Beispiel für Backend. Für Frontend 'package.json' adden.
git add pom.xml
git commit -m "chore: Bump version to 0.1.0"
git push -u origin chore/release-v0.1.0(Jetzt den PR auf GitHub erstellen, reviewen und per Squash
and Merge in main mergen.)
Der main-Branch enthält jetzt den Code, der offiziell
v0.1.0 ist.
-
Hole den aktuellsten Stand von
main:git checkout main git pull origin main
-
Erstelle einen "annotated" (kommentierten) Tag:
git tag -a v0.1.0 -m "Initial MVP release v0.1.0" -
Pushe diesen neuen Tag auf GitHub (
origin):git push origin v0.1.0
Der gh-Befehl wird im Ordner des Repositories ausgeführt.
Er erkennt automatisch, zu welchem Repo auf GitHub er gehört.
gh release create v0.1.0 --generate-notesWas macht --generate-notes?
gh schaut sich alle Commits in diesem Repo seit dem letzten Tag an.
Es listet automatisch alle gemergedten PRs dieses Repos auf und
gruppiert sie, um eine perfekte Release-Beschreibung zu erstellen.
Der oben beschriebene Prozess ist manuell. Für die Zukunft kann dieser Workflow fast vollständig automatisiert werden.
Eine CI/CD-Pipeline (z.B. eine GitHub Action) wird so konfiguriert, dass sie
bei jedem Merge in main die Commit-Messages liest.
-
Frontend:
semantic-release(JavaScript/npm)- Dieses Tool liest die
feat:/fix:Commits im Frontend-Repo. - Es ändert dann automatisch die
package.json, committet, erstellt den Git-Tag (z.B.v0.2.0) und erstellt die GitHub Release.
- Dieses Tool liest die
-
Backend:
maven-release-plugin(oder JReleaser)- Dies sind die Standard-Tools für das Backend-Repo.
- Sie verwalten die
pom.xml-Versionen (z.B. von0.1.0-SNAPSHOTauf0.1.0und dann auf0.1.1-SNAPSHOT). - Sie können ebenfalls automatisiert werden, um Tags und Releases zu erstellen.
-
GitHub Auto-Generated Release Notes
- Dies ist die Funktionalität, die wir im manuellen Prozess mit
gh release create --generate-notesnutzen. - Wichtig: Wenn wir unsere PR-Titel (nicht nur die Commits) im
"Conventional Commit"-Stil schreiben (z.B.
feat: Add login page), kann GitHub die Release Notes automatisch in "Features", "Bugfixes" etc. gruppieren, da es beim "Squash and Merge" den PR-Titel als Commit-Message für den Merge aufmainverwendet.
- Dies ist die Funktionalität, die wir im manuellen Prozess mit
Der in den vorigen Abschnitten beschriebene "manuelle" Release-Prozess hat
noch einen manuellen Schritt: Er erstellt zwar die Release-Notizen (gh release create --generate-notes), hängt aber keine Dateien (wie die .jar- oder
Frontend-dist-Dateien) an.
Diesen Schritt können (und sollten) wir ebenfalls automatisieren.
Der neue Workflow ändert sich leicht. Anstatt dass wir gh release create
lokal ausführen (Schritt 5), lassen wir eine GitHub Action die gesamte
Release-Erstellung übernehmen, sobald sie einen neuen Tag erkennt.
Der neue lokale Prozess:
chore/release-vX.Y.Z-Branch erstellen.pom.xml/package.jsonändern.- PR erstellen und mergen.
mainpullen.git tag -a vX.Y.Z -m "..."git push origin vX.Y.Z<-- DAS IST DER AUSLÖSER (TRIGGER)
Der automatische GitHub Action Prozess:
- Die Action wird durch den neuen Tag-Push ausgelöst.
- Sie checkt den Code (des Tags) aus.
- Sie installiert die nötige Umgebung (z.B. Java/Maven).
- Sie führt den Build-Befehl aus (z.B.
mvn package). - Sie erstellt die Release (wie
gh release create ...) UND hängt die Artefakte (die.jar-Datei aus demtarget-Ordner) an die Release an.
Dies ist ein Beispiel für eine Action-Datei, die wir im Backend-Repo
unter .github/workflows/release-backend.yml erstellen können. Eine
ähnliche Datei (mit npm run build) würde im Frontend-Repo liegen.
name: Create Release and Upload Artifact
# Auslöser (Trigger):
on:
push:
tags:
- "v*.*.*" # Startet nur, wenn ein Tag gepusht wird, der wie v1.2.3 aussieht
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
# 1. Code (des Tags) auschecken
- name: Checkout code
uses: actions/checkout@v5
# 2. Java (z.B. Version 17) installieren
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: "25"
distribution: "temurin"
cache: "maven" # Beschleunigt zukünftige Builds
# 3. Das Projekt bauen (erzeugt die .jar Datei)
# Das 'clean package' stellt sicher, dass alles neu gebaut wird.
# '-B' = Batch-Modus (für Server)
- name: Build with Maven
run: mvn -B clean package
# 4. Release erstellen UND Artefakt anhängen
# Dies ist der wichtigste Schritt.
# Der Befehl 'gh release create' kann Dateipfade als Argumente entgegennehmen.
# GITHUB_TOKEN ist ein geheimer Token, den die Action automatisch erhält.
- name: Create Release and Upload Artifact
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Finde den Namen der .jar-Datei (da er die Version enthält)
JAR_FILE=$(find target -name "*.jar" | head -n 1)
# Erstelle die Release mit Notizen UND hänge die .jar-Datei an
gh release create ${{ github.ref_name }} \
--generate-notes \
"$JAR_FILE"-
Offizielle Git-Webseite & Dokumentation
- Das komplette "Pro Git" Buch online, sowie die offizielle Dokumentation.
- Offizielle Git-Webseite
-
Offizielle GitHub CLI Dokumentation
- Die Dokumentation für
ghmit Installationsanleitungen und einer vollständigen Befehlsreferenz. - GitHub Docs: GitHub CLI
- Die Dokumentation für
-
GitHub Flow (Unser Workflow)
- Offizielle Anleitung (GitHub Docs): Die beste und direkteste Erklärung, was GitHub Flow ist und wie es funktioniert.
- Original-Webseite: Die ursprüngliche Webseite, die die Philosophie dahinter erklärt
-
Gitflow (Komplexerer Workflow zum Vergleich)
- Atlassian Tutorial: Erklärung des alternativen, komplexeren
Gitflow-Modells (mit
develop-Branch).
- Atlassian Tutorial: Erklärung des alternativen, komplexeren
Gitflow-Modells (mit
-
Conventional Commits (Unsere Commit-Benennung)
- Offizielle Spezifikation: Die Grundlage für
feat:,fix:,chore:, etc. Hier sind alle Regeln und Typen definiert.
- Offizielle Spezifikation: Die Grundlage für
-
Semantic Versioning (Unsere Versionierung)
- Offizielle Spezifikation: Die exakte Definition von
MAJOR.MINOR.PATCHund den Regeln.
- Offizielle Spezifikation: Die exakte Definition von
-
Branch-Benennung (Best Practices)
- Es gibt keinen einzigen "offiziellen" Standard für Branch-Namen (wie bei Commits), aber es gibt eine weit verbreitete "Best Practice", die wir verwenden.
- Primäre Quelle (Microsoft): Die offizielle Dokumentation von Microsoft
Azure DevOps empfiehlt exakt die Präfix-Struktur, die wir verwenden
(
feature/,bugfix/,hotfix/). - Alternative Quellen (Artikel): Diese Blog-Artikel fassen gängige und sinnvolle Vorgehensweisen ebenfalls gut zusammen.
- Weiterführende Lektüre (Formaler Standard): Vorschlag, Branch-Namen ähnlich formal wie "Conventional Commits" zu gestalten.
Dies ist ein häufiges Szenario: Du hast Feature A fertig und einen PR erstellt. Deine Kollegen haben aber noch keine Zeit für ein Review. Du möchtest nicht warten, sondern direkt mit Feature B weitermachen, welches aber auf dem Code von Feature A aufbaut.
Man nennt dies "Stacked Branches" (gestapelte Branches).
Wenn du Feature B startest, während Feature A noch nicht in main ist, musst du Feature B von Feature A abzweigen (nicht von main).
Der kritische Moment kommt beim Mergen:
Feature Awird inmaingemerged und der BranchFeature Awird gelöscht.- Dein PR für
Feature Bzeigt aber immer noch auf den (jetzt gelöschten) BranchFeature Aals Basis. - Fehler: Wenn du jetzt versuchst, PR B in den "toten" Branch A zu mergen, landen deine Commits im Nichts. Sie kommen nie in
mainan.
So gehst du vor, um sicher mit gestapelten Branches zu arbeiten:
1. Starten (Der Stack)
- Du befindest dich auf
feature/A(dein fertiger Branch). - Erstelle den neuen Branch von hier aus:
git checkout -b feature/B - Arbeite an
feature/B, committe und pushe. - Erstelle einen PR für
feature/Bund setze als "Base" (Ziel) den Branchfeature/A(nichtmain!).- Vorteil: Der Reviewer sieht im PR B nur die neuen Änderungen von B, nicht nochmal alles von A.
2. Auflösen (Das "Re-Targeting")
Sobald Feature A approved und in main gemerged wurde:
- Lösche den Branch
feature/Aauf GitHub (der übliche Button nach dem Merge). - Gehe sofort zu deinem offenen PR für Feature B.
- GitHub wird oft schon warnen, dass die Basis fehlt.
- Klicke oben neben dem Titel auf "Edit" (oder "Change base").
- Ändere die Basis (Base Branch) von
feature/Aaufmain. - Resultat: Da
feature/Ajetzt Teil vonmainist, zeigt der PR B nun korrekt nur noch die Differenz (deine neuen Commits) im Vergleich zumainan. - Jetzt kann PR B ganz normal reviewed und gemerged werden.