Files
Projektwissen/docs/leitfaden/05_git_arbeitsweise.md
AndreasTharangandClaude Sonnet 5 ab416fb34c Projektwissen: Git-Vorgaben, Ticketzugriff, Tests und Einstieg
Erster Stand des Repositories AG_QGIS/Projektwissen (bisher Arbeitstitel
"Workspace", ADR 0006). Der lokale Ordner heisst weiter AG_QGIS, weil darin
auch die Plugin-Klone liegen.

Git verbindlich (ADR 0007), aus dem bisherigen Wiki-Konzept entwickelt:
- docs/leitfaden/05_git_arbeitsweise.md mit Kanal-Kette, Branch-Namen und
  Gitea-Branch-Schutz.
- Der Einstiegspunkt eines Fixes richtet sich nach dem Kanal, in dem der
  Fehler sitzt; ein Fix an testing oder stable ist erst mit der
  Rueckfuehrung nach unten abgeschlossen. Das fehlte bisher.
- Der stabile Kanal heisst stable, nicht main: der Release-Workflow in
  Repository:hidden/workflows fuehrt git checkout "$CHANNEL" aus, der
  Branchname muss also dem Kanalnamen entsprechen. Er existiert in keinem
  Plugin-Repo und ist vom Maintainer anzulegen.
- Der Mensch drueckt ab: .claude/settings.json sperrt push, merge, tag.
- scripts/hallo.py und /hallo holen den Stand aller Klone, per
  Fast-Forward wo gefahrlos; nie mergen, stashen oder verwerfen.

Ticketzugriff:
- scripts/gitea.py liest Issues, Kommentare und PRs ueber die oeffentliche
  API, ohne Token, nur GET. Schreibendes nur als Entwurf in entwuerfe/.
- Skill sn-ticket.

Tests (ADR 0009):
- docs/leitfaden/06_tests.md: Testebenen, Testpflicht, und wie eine
  Fachperson beurteilt, ob Tests fachlich sinnvoll sind.
- scripts/testkatalog.py erzeugt docs/tests/testkatalog.md per ast-Parsing,
  ohne Import und ohne QGIS. Befund: nur 100 von 332 Tests haben einen
  Docstring, sn_basis keinen einzigen von 87.
- Vorlage und erste Testkonzept-Seite mit Mermaid. Dabei gefunden und gegen
  origin geprueft: _ermittle_gebietstyp_aus_fbschl hat keinen Test, obwohl
  PR #44/#45 genau diese Funktion tolerant gemacht hat.
- docs/konzept/07_qgis_tests_plan.md: Stufenplan fuer Tests gegen echtes
  QGIS. Dabei aufgefallen: QGIS 3.40 ist seit Januar 2026 End of Life,
  qgis_min steht aber noch darauf.

Werkzeuge (ADR 0008):
- 04_werkzeuge_einrichten.md nur noch Claude Code als CLI und in VS Code.
- .vscode/ entfernt, brauchbare Einstellungen als persoenliche Vorlage.

Ausserdem: README als Einstieg neu aufgebaut, Mermaid-Diagramm in
schnittstellen.md repariert (unmaskierte Klammern, rendert seither nicht).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 11:57:26 +02:00

13 KiB

Git-Arbeitsweise — verbindlich für alle Repositories

Stand 04.09.2026. Diese Regeln gelten für jedes Repository der Organisation AG_QGIS, für Menschen und für KI-Agenten gleichermaßen. Die Kurzfassung für den Agenten steht in AGENTS.md; hier steht das Vollständige mit Begründung. Wer eine Abweichung braucht, macht ein Issue auf — nicht einfach einen Push.

Die goldene Regel

In stable, testing und unstable wird nicht entwickelt. Diese Branches nehmen ausschließlich fertige Arbeit per Pull Request entgegen. Entwickelt wird in kurzlebigen Branches, die nach dem Merge gelöscht werden.

Und: Der Mensch drückt ab. Agenten bereiten alles vor. Push, Merge und Tag macht eine Person mit ihrem eigenen Zugang.

1. Die drei Kanäle

Jedes Plugin-Repository hat drei geschützte Branches. Sie entsprechen genau den drei QGIS-Plugin-Feeds im Repository Repository (plugins.xml, plugins-testing.xml, plugins-unstable.xml).

Branch Bedeutung Feed Tag-Suffix Direkter Push
stable stabile Releases, produktionsreif plugins.xml ohne Suffix nein
testing Release-Kandidaten, wird getestet plugins-testing.xml -t nein
unstable fertige Features, noch nicht vollständig getestet plugins-unstable.xml -u nein
flowchart LR
    F["feature/123-kurzname<br/>bugfix/456-kurzname"] -->|"Pull Request"| U["unstable<br/><i>Arbeitsstand</i>"]
    U -->|"Pull Request"| T["testing<br/><i>Release-Kandidat</i>"]
    T -->|"Pull Request"| M["stable<br/><i>stabil</i>"]
    U -.->|"Tag v26.9.1-u"| RU(["Feed unstable"])
    T -.->|"Tag v26.9.1-t"| RT(["Feed testing"])
    M -.->|"Tag v26.9.1"| RM(["Feed stable"])

    style U fill:#fff4e6,stroke:#d9822b
    style T fill:#e6f2ff,stroke:#2b7dd9
    style M fill:#e8f6ec,stroke:#2f9e44

Stand heute (04.09.2026): stable existiert in den Plugin-Repositories noch nicht und muss vom Maintainer angelegt werden (siehe docs/konzept/08_repo_einrichten.md). Bis dahin endet die Kette bei testing, und der stabile Feed bleibt leer. Der Branch oldstable in Plugin_SN_Basis und Plugin_SN_Plan41 ist eine Altlast aus der Zeit davor; er wird nicht mehr bespielt und nach dem Anlegen von stable archiviert oder gelöscht.

Warum stable und nicht main? Der Branchname ist hier nicht frei wählbar. Der Release-Workflow im Repository Repository (Branch hidden/workflows) klont das Plugin-Repo und führt git checkout "$CHANNEL" aus. $CHANNEL kommt aus dem Tag-Suffix und ist unstable, testing oder stable. Der Branch muss also genauso heißen wie der Kanal. Ein Branch main würde den stabilen Release-Pfad brechen, solange die Infrastruktur nicht mit angepasst wird (ADR 0007).

2. Der normale Weg: ein Feature

# 1. Kanal-Branch aktualisieren (macht auch /hallo bzw. python scripts/hallo.py)
cd Plugin_SN_Verfahrensgebiet
git switch unstable
git pull --ff-only

# 2. Eigenen Branch abzweigen — immer von unstable, nie von stable oder testing
git switch -c feature/41-fbschl-feldname

# 3. In kleinen Schritten arbeiten und committen
git add functions/verfahrensgebiet_shape_komplett.py tests/test_shape_komplett.py
git commit -m "Shape-Import akzeptiert Feldnamen FBSchl. mit Punkt (#41)"

# 4. Tests
python ../scripts/run_tests.py sn_verfahrensgebiet --baseline

# 5. Push — durch den Menschen, mit dessen Zugangsdaten
git push -u origin feature/41-fbschl-feldname

Danach im Gitea-Browser einen Pull Request nach unstable öffnen, nach der Vorlage docs/vorlagen/pull_request.md, mit Übergabenotiz (Skill sn-uebergabe).

Ein Pull Request sollte an einem Tag entstehen und in einer Viertelstunde reviewbar sein. Mehr als etwa 400 geänderte Zeilen heißt: das Issue war zu groß.

3. Branch-Namen

Präfix Beispiel Wofür
feature/ feature/41-fbschl-feldname neue Funktion
bugfix/ bugfix/57-basis-laedt-ohne-plan41 Fehlerbehebung
hotfix/ hotfix/61-absturz-beim-beenden dringender Fix auf stable
doku/ doku/git-arbeitsweise nur Dokumentation, ohne Issue zulässig
release/ release/26.9.1 Release-Vorbereitung, nur Maintainer

Regeln für den Namen: Kleinbuchstaben, ASCII, Bindestriche statt Leerzeichen. Keine Umlaute, kein ß, keine Punkte. Issue-Nummer direkt nach dem Präfix, damit Gitea den Branch dem Ticket zuordnet.

Gegenbeispiele aus dem Bestand, die es künftig nicht mehr geben soll:

Vorhanden Problem Richtig wäre
feature/Drucklayout-überarbeiten Umlaut, Großbuchstabe, keine Issue-Nummer feature/37-drucklayout
bug/crash_on_exit Präfix bug/ statt bugfix/, Unterstriche, keine Nummer bugfix/61-absturz-beim-beenden
alkis-nur-laden-stop gar kein Präfix feature/43-alkis-stop-abfrage
fix-fbschl-feldname Präfix fix- gibt es nicht bugfix/45-fbschl-feldname

4. Wo fange ich bei einem Fix an?

Das ist die Frage, bei der am meisten schiefgeht. Sie hängt nicht davon ab, wie dringend der Fehler ist, sondern davon, in welchem Kanal er sitzt.

flowchart TD
    A{"In welchem Kanal<br/>tritt der Fehler auf?"}
    A -->|"nur in unstable"| B["Branch von unstable<br/>PR nach unstable"]
    A -->|"in einem testing-Kandidaten"| C["Branch von testing<br/>PR nach testing"]
    A -->|"in einem stable-Release"| D["Branch von stable<br/>PR nach stable"]

    B --> B2(["fertig"])
    C --> C2["Rückführung:<br/>PR testing → unstable"]
    D --> D2["Rückführung:<br/>PR stable → testing"]
    D2 --> D3["Rückführung:<br/>PR testing → unstable"]
    C2 --> E(["fertig"])
    D3 --> E

    style C fill:#e6f2ff,stroke:#2b7dd9
    style D fill:#ffe9e9,stroke:#d94b2b
    style C2 fill:#fff4e6,stroke:#d9822b
    style D2 fill:#fff4e6,stroke:#d9822b
    style D3 fill:#fff4e6,stroke:#d9822b
Fehler sitzt in Branch von Pull Request nach Danach zwingend
nur unstable unstable unstable
testing-Kandidat testing testing Rückführung testingunstable
stable-Release stable stable Rückführung nach testing und unstable

Warum die Rückführung nicht optional ist

Ein Fix, der nur in testing landet, ist beim nächsten Hochstufen wieder weg: dann wird unstable nach testing gemergt, und unstable kennt den Fix nicht. Der Fehler kommt zurück, und niemand versteht warum. Deshalb gehört zu jedem Fix, der nicht in unstable beginnt, ein zweiter Pull Request — sofort, nicht „später".

# Fix in einem testing-Kandidaten
git switch testing
git pull --ff-only
git switch -c bugfix/61-absturz-beim-beenden
# ... beheben, testen, committen ...
git push -u origin bugfix/61-absturz-beim-beenden
# PR nach testing öffnen und mergen lassen

# Rückführung, direkt im Anschluss
git switch testing && git pull --ff-only
git switch -c doku/rueckfuehrung-61-nach-unstable testing
git push -u origin doku/rueckfuehrung-61-nach-unstable
# PR nach unstable öffnen: "Rückführung Fix #61 aus testing"

Führt die Rückführung zu Konflikten, weil unstable inzwischen weit vorausgelaufen ist, wird der Fix dort neu angewendet (git cherry-pick <commit>) — auch das als eigener Branch mit eigenem Pull Request.

5. Tags und Releases

Version ist JJ.M.N — Jahr, Monat, laufende Nummer im Monat. Beispiel: 26.9.1 ist das erste Release im September 2026. Jeder Kanal zählt getrennt hoch.

Kanal Tag Wird gebaut aus
unstable v26.9.1-u Kopf von unstable
testing v26.9.1-t Kopf von testing
stable v26.9.1 Kopf von stable

Achtung: Der Workflow baut den Kopf des Kanal-Branches, nicht den getaggten Commit. Vor dem Taggen also sicherstellen, dass der Branch genau den gewünschten Stand hat.

Tags setzt ausschließlich ein Maintainer. Ablauf und Prüfliste: Skill sn-release.

6. Was der Agent darf und was nicht

Der Agent darf Der Agent darf nicht
git fetch, git pull --ff-only, git status, git log, git diff git push in jeder Form
lokale Branches anlegen und wechseln git merge, git rebase
git add, git commit auf einem Arbeitsbranch git tag
Tests laufen lassen, changelog.txt ergänzen Pull Requests mergen
Issue- und PR-Texte als Entwurf vorbereiten git reset --hard, git push --force, git clean
Tickets über scripts/gitea.py lesen irgendetwas auf dem Gitea-Server verändern
docs/status/testbaseline.json ändern

Das ist nicht nur eine Bitte. .claude/settings.json im Repo verbietet die entsprechenden Kommandos technisch; der Agent bekommt eine Ablehnung statt einer Ausführung. Wer die Regel für einen Einzelfall aussetzen will, tut das bewusst und lokal, nicht im Repo.

Warum so streng: Ein Push trägt den Namen einer Person und ihre Verantwortung. Ein Agent kann fachlich nicht beurteilen, ob ein Stand veröffentlichungsreif ist — und ein versehentlicher Push auf einen Kanal-Branch trifft sofort alle anderen Behörden.

7. Branch-Schutz auf Gitea einrichten (Maintainer)

Gitea 1.27, je Repository unter Einstellungen → Branches (englisch: Settings → Branches), dort eine neue Branch-Schutzregel anlegen. Für jeden der drei Kanäle eine Regel:

Einstellung Wert Wirkung
Branch-Name stable bzw. testing, unstable betrifft genau diesen Branch
Push deaktivieren an kein direkter Push, nur Merge über Pull Request
Merge-Freigabe erforderlich mindestens 1 Review durch eine andere Person ist Pflicht
Statusprüfungen erforderlich an, sobald CI läuft Tests müssen grün sein (Vorlage docs/vorlagen/gitea_workflow_tests.yaml)
Veraltete Freigaben verwerfen an ein neuer Push macht das Review ungültig

Zusätzlich den Standard-Branch auf unstable belassen — dort landet die tägliche Arbeit, und ein neu geklontes Repo steht damit sofort richtig.

8. Aufräumen

Nach dem Merge wird der Arbeitsbranch gelöscht — in Gitea per Schaltfläche direkt am gemergten Pull Request, lokal so:

git switch unstable
git pull --ff-only
git branch -d feature/41-fbschl-feldname
git fetch --prune

Nicht gelöschte Branches sammeln sich an und niemand weiß später, ob sie noch etwas enthalten. Im Bestand liegen davon derzeit vier herum (feature/Drucklayout-überarbeiten, print_layout, alkis-nur-laden-stop, fix-fbschl-feldname) — die sind zu prüfen und dann zu entfernen.

9. Commit-Nachrichten

Deutsch, Präsens, erste Zeile höchstens 72 Zeichen, Issue-Nummer am Ende in Klammern.

Shape-Import akzeptiert Feldnamen FBSchl. mit Punkt (#41)

DAVID-Exporte liefern das Feld teils mit, teils ohne Punkt. Die Suche
prüft jetzt beide Schreibweisen, die Bedeutung der Schlüssel 901/10110F
und 901/10120F bleibt unverändert.

Was die Nachricht beantworten muss: was ändert sich und warum. Das Wie steht im Diff. Nicht brauchbar: „Fix", „Update", „Änderungen", „wip".

10. Sitzungsbeginn

Vor dem ersten Handgriff — auch wenn es „nur schnell etwas" ist:

python scripts/hallo.py        # oder in Claude Code: /hallo

Das holt für alle Klone den Stand vom Server (git fetch), aktualisiert die Kanal-Branches per Fast-Forward, wo das gefahrlos möglich ist, und meldet alles Übrige, ohne es anzufassen. Es merged nicht, es stasht nicht, und es fasst keine ungesicherten Änderungen an.

Ohne diesen Schritt entstehen Konflikte, die niemand braucht — und im schlimmsten Fall wird ein Fehler behoben, den jemand anderes vor drei Tagen schon behoben hat.

11. Häufige Fehler

„Ich habe direkt auf unstable committet." Solange nichts gepusht ist, ist das reparabel: git switch -c feature/<nr>-<name> legt einen Branch auf dem aktuellen Stand an, danach git switch unstable && git reset --hard origin/unstable. Der reset ist hier zulässig, weil er nur die lokale Kopie auf den Serverstand zurücksetzt — trotzdem vorher git log prüfen.

„Mein Branch ist hinter unstable." Vor dem Pull Request aktualisieren: git switch unstable && git pull --ff-only, dann zurück auf den Arbeitsbranch und git merge unstable. Kein rebase auf bereits gepushten Branches — das schreibt Historie um, die andere schon haben.

git pull will einen Merge-Commit machen." Dann ist der lokale Branch vorausgelaufen. --ff-only bricht in dem Fall bewusst ab. Erst klären, was die eigenen Commits sind, statt blind zu mergen.

„Der Fix ist wieder weg." Fast immer die fehlende Rückführung aus Abschnitt 4.

„Ich habe im falschen Repo gearbeitet." Passiert, weil alle Klone nebeneinander liegen. git status zeigt oben den Pfad; python scripts/hallo.py zeigt alle Repos auf einmal.

Siehe auch

  • AGENTS.md — Kurzfassung der harten Regeln
  • docs/leitfaden/03_arbeitsweise.md — der Arbeitszyklus vom Issue bis zum Merge
  • docs/leitfaden/06_tests.md — was vor dem Pull Request grün sein muss
  • docs/entscheidungen/0007-branchmodell.md — warum das Modell so aussieht
  • docs/konzept/08_repo_einrichten.mdstable anlegen, Branch-Schutz setzen
  • Skill sn-release — Tags und Releases