Git-Workflow für Shopware-Plugins: Eigenes Repository oder GitHub? (Teil 3)

Serie: Professionelle Shopware-Entwicklungsumgebung

  1. Entwicklungsumgebung einrichten (DDEV + Docker)
  2. Git-Workflow für Plugin-Entwicklung (dieser Artikel)
  3. Testen und Qualitätssicherung
  4. Deployment und Updates

Du hast deine Entwicklungsumgebung aufgesetzt und ein erstes Plugin-Gerüst erstellt. Aber was passiert, wenn du eine Änderung machst, die alles kaputt macht? Ohne Git hast du ein Problem. Mit Git hast du einen Rücksprungpunkt. In diesem Teil zeige ich dir, wie du Versionskontrolle für deine Shopware-Plugins einrichtest — und warum das auch als Solo-Entwickler keine Option, sondern Pflicht ist.

Warum Versionskontrolle?

Stell dir vor, du arbeitest an einer Versandkosten-Berechnung. Du änderst drei Dateien, testest im Browser — und plötzlich funktioniert der gesamte Checkout nicht mehr. Ohne Git fängt jetzt das hektische Suchen an: Was habe ich geändert? Welche Datei war es? War der Stand von gestern noch korrekt?

Mit Git ist die Antwort ein Einzeiler: git diff zeigt dir exakt, was sich geändert hat. git checkout -- . setzt alles auf den letzten gesicherten Stand zurück. Kein Raten, kein Suchen.

Aber Versionskontrolle kann noch mehr:

  • Code-History: Jeder Stand deines Plugins ist gespeichert. Du kannst jederzeit nachschauen, wann du eine bestimmte Funktion eingebaut hast — und warum.
  • Parallele Entwicklung: Mit Branches arbeitest du an neuen Features, ohne den stabilen Stand zu gefährden.
  • Zusammenarbeit: Sobald ein zweiter Entwickler am Plugin mitarbeitet, ist Git keine Empfehlung mehr — es ist die einzige sinnvolle Option.
  • Backup: Dein Code liegt nicht nur auf einem Rechner. Er ist auf dem Server, auf GitHub, oder auf beidem.

Auch als Solo-Entwickler wirst du Git nach einer Woche nicht mehr missen wollen. Spätestens wenn du einen Bug in der Produktion fixen musst und gleichzeitig an einem neuen Feature arbeitest, wirst du froh sein, dass du Branches hast.

Zwei Wege zum eigenen Repository

Für dein Shopware-Plugin brauchst du ein zentrales Repository, in das du deinen Code pushst. Dafür gibt es zwei sinnvolle Optionen — und beide sind valide.

Option A: Eigenes Git-Repository auf dem VPS

Wenn du bereits einen VPS für deine Entwicklungsumgebung betreibst, liegt es nahe, auch dein Repository dort zu hosten. Du erstellst dafür ein sogenanntes Bare-Repository — ein Repository ohne Arbeitskopie, das nur als zentraler Speicher dient.

Bare-Repository auf dem Server anlegen

Verbinde dich per SSH mit deinem Server:

ssh devbox
mkdir -p /workspace/git/RcMeinPlugin.git
cd /workspace/git/RcMeinPlugin.git
git init --bare

Das --bare ist wichtig: Es erstellt ein Repository ohne Arbeitsverzeichnis. Niemand arbeitet direkt auf dem Server an den Dateien — der Server nimmt nur Pushes entgegen und speichert die History.

Lokal verbinden und ersten Commit pushen

cd /pfad/zum/plugin
git init
git remote add origin devbox:/workspace/git/RcMeinPlugin.git
git add -A
git commit -m "Initiales Plugin-Setup"
git push -u origin main

Ab jetzt kannst du lokal arbeiten, committen und auf den Server pushen. Push und Pull gehen über dein lokales Netzwerk oder VPN — das bedeutet Millisekunden statt Sekunden.

Vorteile

  • Geschwindigkeit: Push und Pull laufen über LAN oder VPN — spürbar schneller als über das Internet
  • Volle Kontrolle: Deine Daten liegen auf deinem Server, nicht bei einem externen Anbieter
  • Kein Vendor-Lock-in: Du bist an keinen Dienst gebunden
  • Private Entwicklung: Kein Konto bei einem Drittanbieter nötig, keine Sichtbarkeitseinstellungen

GitHub jederzeit nachrüsten

Das Schöne an Git: Du kannst jederzeit ein zweites Remote hinzufügen. Wenn du dein Plugin später auf GitHub veröffentlichen willst, ist das ein Dreizeiler:

git remote add github git@github.com:user/RcMeinPlugin.git
git push github main

Dein VPS bleibt das Haupt-Remote für die tägliche Arbeit. GitHub dient als Backup, für Open-Source-Veröffentlichung oder für CI/CD.

Option B: Direkt mit GitHub arbeiten

Wenn du keinen eigenen Server betreibst oder den Verwaltungsaufwand scheust, kannst du dein Repository direkt auf GitHub anlegen. Das ist der einfachere Weg — besonders für Einsteiger.

Repository erstellen und verbinden

Du kannst das Repository über die GitHub-Weboberfläche erstellen oder direkt über die Kommandozeile:

cd /pfad/zum/plugin
git init
git remote add origin git@github.com:user/RcMeinPlugin.git
git add -A
git commit -m "Initiales Plugin-Setup"
git push -u origin main

Vorteile

  • Kein Server nötig: Kein eigenes Repository verwalten, keine Backups einrichten
  • CI/CD sofort verfügbar: GitHub Actions lassen sich direkt nutzen — automatische Tests, Code-Analyse, Deployment
  • Projekt-Management: Issues, Pull Requests, Projekt-Boards — alles integriert
  • Community: Wenn du dein Plugin als Open Source veröffentlichst, ist GitHub die etablierte Plattform

Nachteile

  • Abhängigkeit: Dein Code liegt bei einem externen Dienst. Wenn GitHub offline ist, kannst du nicht pushen.
  • Geschwindigkeit: Push und Pull laufen über das Internet — bei großen Repositories oder langsamer Leitung spürbar
  • Privatsphäre: Auch bei privaten Repositories liegen deine Daten auf fremden Servern

Welche Option passt zu dir?

Beide Wege sind absolut valide. Wenn du bereits einen VPS für deine Entwicklungsumgebung hast, ist Option A der logische Schritt — du nutzt vorhandene Infrastruktur und hast maximale Kontrolle. Wenn du schnell starten willst und keinen eigenen Server betreibst, ist GitHub die pragmatische Wahl. Du kannst die Entscheidung auch jederzeit ändern: Ein Git-Remote lässt sich in Sekunden hinzufügen oder entfernen.

Die richtige .gitignore für Shopware-Plugins

Bevor du deinen ersten Commit machst, brauchst du eine .gitignore-Datei. Sie legt fest, welche Dateien nicht ins Repository gehören. Das klingt trivial, ist aber einer der häufigsten Fehler bei Einsteigern: Wer alles committet, hat schnell ein aufgeblähtes Repository mit sensiblen Daten drin.

Hier ist die .gitignore, die du für jedes Shopware-Plugin verwenden solltest:

# Abhängigkeiten — werden über Composer installiert, nicht versioniert
/vendor/

# Cache und Build-Artefakte
/var/
.php-cs-fixer.cache
.phpunit.cache
.phpunit.result.cache

# IDE-Konfigurationen — jeder Entwickler nutzt eigene Einstellungen
.idea/
.vscode/
*.swp
*.swo

# Betriebssystem-Dateien
.DS_Store
Thumbs.db
desktop.ini

# Umgebungskonfiguration — enthält sensible Daten
.env
.env.local
.env.*.local

# Node.js (falls Storefront-Assets gebaut werden)
/node_modules/

Lass uns die einzelnen Gruppen durchgehen — denn jede hat ihren Grund.

vendor/ — Abhängigkeiten gehören nicht ins Repository

Das vendor/-Verzeichnis enthält alle Pakete, die Composer herunterlädt. Bei einem typischen Shopware-Plugin können das hunderte Megabytes sein. Diese Dateien werden durch composer install automatisch generiert — sie ins Repository zu packen, wäre wie ein Backup deines Downloads-Ordners. Unnötiger Ballast, der bei jedem Update zu riesigen Diffs führt.

Die composer.json und composer.lock hingegen gehören ins Repository. Sie definieren exakt, welche Versionen installiert werden sollen. Damit kann jeder Entwickler (oder dein Server) mit einem einzigen Befehl den identischen Stand herstellen.

var/ — Cache und temporäre Dateien

Shopware legt im var/-Verzeichnis Cache-Dateien, Logs und temporäre Daten ab. Die werden bei jedem cache:clear neu generiert und sind maschinenspezifisch. Ein Cache vom Entwicklungsrechner ist auf dem Produktivserver nutzlos — schlimmer noch, er kann Probleme verursachen.

IDE-Dateien — persönliche Einstellungen

.idea/ (PhpStorm), .vscode/ (VS Code) und Swap-Dateien wie *.swp enthalten die persönlichen Editor-Einstellungen des jeweiligen Entwicklers. Schriftgröße, Farbschema, Debugger-Konfiguration — das gehört nicht in den gemeinsamen Code. Jeder Entwickler richtet seine IDE so ein, wie er am besten arbeiten kann.

.env — Sensible Daten, niemals versionieren

Die .env-Datei enthält Datenbankpasswörter, API-Keys, Server-URLs und andere Konfiguration, die sich zwischen Umgebungen unterscheidet. Diese Datei darf unter keinen Umständen ins Repository. Ein versehentlich gepushtes Datenbankpasswort ist ein Sicherheitsrisiko — und die Git-History vergisst nichts. Selbst wenn du die Datei später löschst, bleibt sie in der History erhalten.

node_modules/ — JavaScript-Abhängigkeiten

Falls dein Plugin Storefront-Assets mitbringt, hast du möglicherweise ein package.json und ein node_modules/-Verzeichnis. Für node_modules gilt dasselbe wie für vendor/: Es wird durch npm install generiert und kann tausende Dateien umfassen. Ins Repository gehört nur die package.json (und package-lock.json).

Saubere Commits schreiben

Ein Commit ist mehr als ein Speicherpunkt. Er ist eine Nachricht an dein zukünftiges Ich — und an jeden, der jemals an diesem Code arbeiten wird. Die Qualität deiner Commit-Messages entscheidet darüber, ob die Git-History nützlich oder nutzlos ist.

Die Grundregel: Ein Commit = eine logische Änderung

Nicht drei Features auf einmal. Nicht „ein bisschen hier, ein bisschen da“. Jeder Commit sollte genau eine Sache tun — und die Commit-Message sollte diese Sache klar benennen.

Schlecht:

Verschiedene Änderungen
Update
Fix
asdf

Gut:

Versandkosten-Berechnung für Auslandslieferungen ergänzt
Mindestbestellwert-Prüfung im Checkout-Subscriber korrigiert
Konfigurationsfelder für Steuer-Mapping hinzugefügt

Ob du auf Deutsch oder Englisch schreibst, ist Geschmackssache — aber bleib konsistent. In einem deutschsprachigen Team sind deutsche Messages absolut in Ordnung.

Vor jedem Commit: git status

Mach dir das zur Gewohnheit. Bevor du commitest, schau dir an, was sich geändert hat:

# Was hat sich geändert?
git status

# Details anzeigen
git diff

# Gezielt Dateien stagen
git add src/Subscriber/CheckoutSubscriber.php
git add src/Service/ShippingCalculator.php

# Commit erstellen
git commit -m "Versandkosten-Berechnung für Ausland ergänzt"

So vermeidest du, dass versehentlich Debug-Dateien, temporäre Testdaten oder andere Überbleibsel im Commit landen.

Branching-Basics

Ein Branch ist eine eigenständige Arbeitskopie deines Codes. Du zweigst vom Hauptstrang ab, arbeitest an einem Feature, und führst die Änderungen erst zusammen, wenn alles fertig und getestet ist. Der Hauptstrang bleibt währenddessen stabil.

So funktioniert es in der Praxis

Nehmen wir an, du willst eine Export-Funktion für Versandkosten einbauen:

# Neuen Branch erstellen und wechseln
git checkout -b feature/versandkosten-export

# ... arbeiten, testen, committen ...
git add src/Service/ShippingExporter.php
git commit -m "CSV-Export für Versandkostenregeln implementiert"

git add src/Controller/ExportController.php
git commit -m "Admin-Route für Versandkosten-Export ergänzt"

# Zurück zum Hauptbranch
git checkout main

# Feature-Branch zusammenführen
git merge feature/versandkosten-export

Warum nicht einfach alles auf main committen?

Solange du alleine an einem kleinen Feature arbeitest, funktioniert das. Aber sobald du an mehreren Dingen gleichzeitig arbeitest, wird es chaotisch. Stell dir vor:

  • Du baust gerade die Export-Funktion (halb fertig, noch nicht getestet)
  • Ein Kunde meldet einen kritischen Bug im Checkout

Ohne Branches hast du jetzt halbfertigen Feature-Code und musst trotzdem einen Fix liefern. Mit Branches wechselst du einfach zurück auf main, erstellst einen hotfix/checkout-bug-Branch, fixst den Fehler und lieferst. Dein halbfertiges Feature wartet sicher in seinem eigenen Branch.

Typische Branch-Struktur

BranchZweck
mainStabiler, getesteter Stand — immer lauffähig
feature/*Neue Funktionen, z.B. feature/steuer-mapping
hotfix/*Dringende Bugfixes für den Produktivstand
refactor/*Code-Umbauten ohne neue Funktionalität

Du musst kein kompliziertes Branching-Modell wie Git Flow einführen. Für die Plugin-Entwicklung reichen main und Feature-Branches. Wichtig ist nur die Grundregel: Auf main liegt immer ein funktionierender Stand.

Der tägliche Workflow auf einen Blick

Hier der typische Ablauf für einen Arbeitstag an deinem Shopware-Plugin:

# 1. Neuen Branch für das aktuelle Feature
git checkout -b feature/mein-neues-feature

# 2. Arbeiten, Änderungen prüfen
git status
git diff

# 3. Gezielt stagen und committen
git add src/relevante-datei.php
git commit -m "Aussagekräftige Beschreibung der Änderung"

# 4. Auf den Server pushen
git push origin feature/mein-neues-feature

# 5. Wenn fertig: in main zusammenführen
git checkout main
git merge feature/mein-neues-feature
git push origin main

Das klingt nach vielen Schritten — wird aber nach ein paar Tagen zur Routine. Und diese Routine schützt dich vor den Momenten, in denen alles schiefgeht.

Wie geht es weiter?

Dein Plugin ist jetzt versioniert, deine Commits sind sauber, und du hast einen Workflow, der mit dir wachsen kann. Im nächsten Teil der Serie schauen wir uns an, wie du dein Plugin automatisiert testest und mit Code-Qualitäts-Tools sicherstellst, dass nichts kaputtgeht.

Die gezeigten Code-Beispiele dienen zur Veranschaulichung. Nutzung auf eigene Verantwortung. Mehr dazu