GitHub Triage
Triage der offenen GitHub Issues und Pull Requests eines Repositorys. Optional können zuerst bereite PRs bearbeitet werden (Merge von bestandenen Bot-PRs und von Maintainer-freigegebenen PRs, Überprüfung noch nie gesichteter PRs), dann Schließen von Issues, die bereits gelöst sind (mit einem Kommentar, der auf den auflösenden PR oder Commit verweist), sicherstellen, dass Issues und die sie behebenden ausstehenden PRs aufeinander verweisen, und nur lokal eine Priorität und eine Änderungsumfangsschätzung für jedes noch offene Issue vergeben.
Wann zu verwenden
- Wenn der Benutzer
/github-triageausführt, um die offenen Issues und Pull Requests eines Repositorys zu groomen oder zu überprüfen. - Wenn ein Issue-Backlog abgedriftet ist: gelöste Arbeit blieb offen, Fixes wurden ohne Schließen des zugehörigen Issues ausgeliefert oder PRs sind unterwegs, die nie mit ihrem Issue verknüpft wurden.
- Wenn sich bereite PRs angesammelt haben (bestandene Abhängigkeits-Updates, genehmigte und grüne PRs) oder PRs ohne Überprüfung herumliegen.
Wann NICHT zu verwenden
- Nicht automatisch aufrufen. Diese Fähigkeit führt irreversibel Schreibvorgänge in GitHub durch (Mergen von PRs, Schließen von Issues, Posten von Kommentaren) und läuft nur bei explizitem Aufruf.
- Nicht verwenden, um Priority/Effort-Labels auf GitHub anzuwenden. Priorität und Umfang werden nur lokal angezeigt und niemals gepostet (siehe Sicherheitsregeln).
- Nicht als Ersatz für die endgültige Merge-Entscheidung eines Menschen verwenden – jeder Merge wird zur expliziten Genehmigung vorgeschlagen und nie autonom durchgeführt.
Kernprinzipien
- Schreibvorgänge sind abgesichert. Die vollständige Triage zuerst berechnen, jeden vorgeschlagenen Schreibvorgang – einschließlich Merges – zur Überprüfung vorlegen und nichts ausführen, bis der Benutzer zustimmt.
- Nachweis vor dem Schließen. Niemals ein Issue ohne einen konkreten, zitierten Grund schließen (ein gemergter PR oder ein Commit auf dem Standardbranch). Wenn der Nachweis schwach oder mehrdeutig ist, das Issue offen lassen und zur Überprüfung markieren.
- Priorität und Umfang bleiben lokal. Sie sind eine interne Planungshilfe für den Benutzer und werden nie auf GitHub geschrieben.
Arbeitsablauf
Phase 0: Ziel-Repository auswählen
gh auth status # Bestätigen, dass gh authentifiziert ist
git rev-parse --is-inside-work-tree # Ist PWD ein git-Repository?
git remote -v # Remote-Repositories auflisten
Bestimmen Sie die Menge der unterschiedlichen, auf GitHub gehosteten Repositorys unter den Remotes. Ein Remote wird auf GitHub gehostet, wenn seine URL-Host github.com ist, in einer dieser Formen:
https://github.com/OWNER/REPO(.git)[email protected]:OWNER/REPO(.git)ssh://[email protected]:OWNER/REPO(.git)
Normalisieren Sie jedes zu OWNER/REPO und deduplizieren Sie (eine Fork-Einrichtung kann origin und upstream auf verschiedene GitHub-Repos verweisen lassen; mehrere Remotes, die auf das gleiche OWNER/REPO verweisen, zählen einmal).
Auswahlregel:
| Situation | Aktion |
|---|---|
| Genau ein eindeutiges GitHub-Repo | Als Standard verwenden – nicht nachfragen. |
| Kein Git-Repo oder null GitHub-Remotes | Den Benutzer nach dem OWNER/REPO für die Triage fragen. |
| Mehr als ein eindeutiges GitHub-Repo | AskUserQuestion verwenden, um den Benutzer das OWNER/REPO auswählen zu lassen. |
GitHub Enterprise-Hosts können nicht zuverlässig automatisch erkannt werden. Wenn der Benutzer auf einer GHE-Instanz arbeitet, nach
OWNER/REPOfragen und ihn bitten,GH_HOSTzu setzen / den konfigurierten Host vonghzu verwenden. Das aufgelöste Repo dem Benutzer bestätigen, bevor fortgefahren wird.
Speichern Sie das Ergebnis als REPO="OWNER/REPO" und übergeben Sie -R "$REPO" an jeden gh-Aufruf. Validieren Sie es gegen ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ vor der Verwendung, damit eine fehlerhafte oder bösartige Remote-URL nie in einen Befehl gelangt.
Phase 1: Issues und Kontext sammeln
# Offene Issues (gh issue list schließt PRs standardmäßig aus)
gh issue list -R "$REPO" --state open --limit 1000 \
--json number,title,body,labels,assignees,comments,reactionGroups,createdAt,updatedAt,url
# Offene PRs – Kandidaten für "ausstehenden Fix" (Issue-Phase) und PR-Triage (Phase 2)
gh pr list -R "$REPO" --state open --limit 1000 \
--json number,title,body,author,isDraft,reviewDecision,latestReviews,\
mergeable,mergeStateStatus,statusCheckRollup,labels,createdAt,headRefName,url,closingIssuesReferences
# Kürzlich gemergte PRs – Kandidaten für "bereits gelöst"
gh pr list -R "$REPO" --state merged --limit 300 \
--json number,title,body,mergedAt,url,closingIssuesReferences
closingIssuesReferences listet die Issues auf, die ein PR zu schließen verknüpft ist – befüllt durch eines von GitHub's Schluss-Schlüsselwörtern (close/closes/closed, fix/fixes/fixed, resolve/resolves/resolved) im PR-Text oder durch eine manuelle UI-Verknüpfung. Es ist das stärkste verfügbare Signal. Für Issues, die es nicht abdeckt, auch Commit-Nachrichten auf dem Standardbranch durchsuchen. Lösen Sie den Standardbranch autoritativ aus dem ausgewählten Repo auf (nicht aus lokalem origin/HEAD, das nicht gesetzt sein oder auf das falsche Remote zeigen kann):
default_branch=$(gh repo view "$REPO" --json defaultBranchRef --jq .defaultBranchRef.name)
# Anker für die Issue-Nummer, damit #12 nicht #120, #123, … matcht
git log --oneline "origin/$default_branch" \
| grep -iE "(close|fix|resolve)[sd]? +#<N>([^0-9]|$)"
Phase 2: Offene Pull Requests triagen (optional)
Behandeln Sie PRs vor Issues: Das Mergen bereiter PRs hier bedeutet, dass die Prüfung auf "bereits gelöst" in der Issue-Phase die Arbeit sieht, die diese Merges gerade ausgeliefert haben.
Wenn es keine offenen PRs gibt, überspringen Sie diese Phase. Andernfalls fassen Sie die offenen PRs zusammen und fragen den Benutzer, ob PRs jetzt behandelt werden sollen (AskUserQuestion: PRs behandeln / zu Issues springen). Wenn er überspringt, gehen Sie direkt zur Issue-Klassifizierung.
Klassifizieren Sie jeden offenen PR anhand seines Review-, CI- und Merge-Status. Die untenstehenden Feldformen sind das, was gh pr ... --json tatsächlich zurückgibt – verlassen Sie sich darauf, nicht auf Ihre Intuition:
- Bereit zum Mergen =
mergeable == "MERGEABLE"undmergeStateStatus == "CLEAN"und CI blockiert nicht (unten).CLEANist GitHub's serverseitiges Urteil "keine Konflikte, nicht zurück, nicht im Entwurf, erforderliche Checks grün" – jeder anderemergeStateStatus(BEHIND,UNSTABLE,BLOCKED,DIRTY,DRAFT, …) ist nicht bereit. Behandeln Siemergeable == "UNKNOWN"(GitHub berechnet Mergeability träge, besonders direkt nach einem anderen Merge) als nicht bereit – kurz neu abfragen oder überspringen; niemals darauf mergen. - CI blockiert nicht –
statusCheckRollupscannen (keyed auf__typename) und den PR nur bei einem echten Problem ablehnen: einem harten Fehler (einCheckRunmitconclusionFAILURE/CANCELLED/TIMED_OUT/ACTION_REQUIRED/STARTUP_FAILURE/STALE, oder einStatusContextmitstateFAILURE/ERROR), oder etwas noch Laufendem (einCheckRunstatusQUEUED/IN_PROGRESS/WAITING/PENDING, oder einStatusContextstatePENDING/EXPECTED– warten, noch nicht mergen).SUCCESS,NEUTRALundSKIPPEDsind in Ordnung und dürfen nicht blockieren (z.B. ein CodeQL-Lauf, derNEUTRALbei einem Abhängigkeits-Bump meldet – ein grüner Dependabot-PR istCLEANmit einemNEUTRAL-CodeQL-Check). Ein leeres Rollup ist kein CI – ein eigener Status, der nie als bereit behandelt wird.mergeStateStatus == "CLEAN"spiegelt bereits den Status erforderlicher Checks wider; verwenden Sie das Rollup, um fehlschlagende/ausstehende nicht erforderliche Checks zu erfassen. - Bot/automatisiert =
author.is_bot == true. Gleichen Sie die Auto-Merge Whitelist gegenauthor.loginab, nachdem Sie die Darstellung vonghnormalisiert haben – entfernen Sie ein führendesapp/und ein nachgestelltes[bot](gh gibt Dependabot in einigen Versionen alsapp/dependabotund in anderen alsdependabot[bot]zurück; normalisieren Sie beide zudependabot). Standardmäßig auf der Whitelist:dependabot,renovate, plus alle, die der Benutzer nennt. Ein bestandener PR von einem nicht auf der Whitelist stehenden Bot wird gemeldet, aber nie zum Merge angeboten. - Maintainer-freigegeben =
latestReviewshat einen Eintrag mitstate == "APPROVED", dessenauthorAssociationOWNER/MEMBER/COLLABORATORist und dessenauthor.loginnicht der PR-Autor ist. Verwenden Sie nichtreviewDecision == "APPROVED"allein: es ist Branch-Protection-gesteuert und istnullin Repos ohne erforderliche Review-Regel, daher vertraut es sowohl zu sehr (kann Schreibzugriff nicht bestätigen) als auch übersieht echte Freigaben. - Nie überprüft =
latestReviewshat keinenAPPROVED/CHANGES_REQUESTED-Eintrag von jemand anderem als dem PR-Autor (ein Fork "Review deaktiviert" Bot-Kommentar ist kein Review).
| Kategorie | Bedingung | Angebotene Aktion |
|---|---|---|
| Mergebarer Bot-PR | Whitelist-Bot + bereit + nicht Entwurf | Biete inkrementellen, in-Reihenfolge-Merge an |
| Freigegeben & bereit | Maintainer-freigegeben + bereit + nicht Entwurf | Zum Mergen auffordern |
| Nie überprüft | Nicht-Bot + nur der Autor hat überprüft (oder keine Reviews) + nicht Entwurf | Biete an, einen Review-Subagenten zu starten |
| Benötigt Arbeit | Entwurf, harter CI-Fehler, ausstehendes CI, Konflikte, zurück, Änderungen angefordert, oder ein Bot-PR, der nicht bereit ist | Nur melden – keine Aktion angeboten |
("Bereit" subsumiert bereits CI-nicht-blockierend. Review-Subagenten sind für von Menschen erstellte PRs – ein Bot-Abhängigkeits-Bump, der nicht bereit ist, wird als "Benötigt Arbeit" gemeldet, nicht überprüft.)
Präsentieren Sie die kategorisierten PRs und bieten Sie die anwendbaren Aktionen über AskUserQuestion an.
Inkrementeller, in-Reihenfolge-Merge (Bot-PRs und freigegebene-bereite PRs): Bestätigen Sie die Merge-Menge und die Merge-Methode zuerst (Mergen ist irreversibel), dann mergen Sie einen nach dem anderen, zuerst den ältesten. Wählen Sie eine Methode, die das Repo zulässt, und schlagen Sie fehl, wenn es keine zulässt:
gh repo view "$REPO" --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed # positionsbasiertes Repo, nicht -R
Für jeden PR in Reihenfolge vor dem Mergen erneut überprüfen (der Zustand ändert sich nach jedem Merge – ein gelandeter PR kann den nächsten BEHIND, in Konflikt oder in Neuberechnung lassen), synchron mergen, dann bestätigen, dass er gelandet ist, bevor fortgefahren wird:
gh pr view <N> -R "$REPO" --json isDraft,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup
# nur fortfahren, wenn noch bereit: nicht Entwurf, mergeable == MERGEABLE, mergeStateStatus == CLEAN, CI blockiert nicht
gh pr merge <N> -R "$REPO" --<method> # niemals --auto, niemals --admin
gh pr view <N> -R "$REPO" --json state # erwarte "MERGED", bevor zum nächsten PR übergegangen wird
Stoppen und melden, wenn ein PR nicht mehr bereit ist (einschließlich mergeable == "UNKNOWN"), wenn der Merge nicht gelandet ist oder wenn ein erforderlicher Check nicht grün ist – niemals erzwingen, --admin, --auto oder einen Check überspringen. Für Bot-PRs den Abhängigkeits- und Versionssprung (z.B. Major-Bumps) im Gate anzeigen, damit der Benutzer mit Kontext entscheiden kann.
Review-Subagenten (nie überprüfte PRs): Wenn der Benutzer zustimmt, einen Agenten pro PR starten – alle in einer einzigen Assistant-Nachricht, damit sie parallel laufen. Jeder Subagent überprüft das Diff eines PRs und gibt ein strukturiertes Review zurück; schreiben Sie jedes in github-pr-<number>-review.md im Arbeitsverzeichnis (vorherige Dateien für diesen PR überschreiben). Reviews sind schreibgeschützt und werden nie auf GitHub gepostet. Siehe
references/reviewing-prs.md für den Subagenten-Prompt, die Review-Rubrik und das Dateiformat.
Nach Merges die Liste der gemergten PRs neu abrufen (die --state merged-Abfrage aus Phase 1), damit die Issue-Phase Issues erkennen kann, die diese Merges gelöst haben.
Phase 3: Jedes offene Issue klassifizieren
Sortieren Sie jedes offene Issue in genau einen Eimer.
Eimer A – Bereits gelöst (die Arbeit ist ausgeliefert, das Issue blieb offen). Erfordert konkrete Beweise; Korroboration einem einzelnen schwachen Signal vorziehen:
- Ein gemergter PR listet das Issue in
closingIssuesReferences, oder sein Titel/Text verweist auf#Nzusammen mit einem Schlüsselwort zum Schließen. (Stärkstes.) - Ein Commit auf dem Standardbranch verweist auf
#Nmit einem Schlüsselwort zum Schließen. - Das Verhalten, das im Issue angefragt wird, existiert nachweislich im aktuellen Code – durch Lesen des relevanten Codes mit Grep/Read überprüfen, nicht annehmen. Eine andere oder teilweise Implementierung löst das Issue nicht.
→ Vorgeschlagener Schreibvorgang: Issue mit einem Kommentar schließen, der den auflösenden PR/Commit nennt.
gh issue close <N> -R "$REPO" \
-c "Gelöst durch #<PR> (<kurzer Grund>). Schließe, da die Änderung jetzt auf $default_branch ist."
Eimer B – Ausstehender PR würde es lösen (ein offener PR adressiert das Issue).
Erkennung in beide Richtungen: Der closingIssuesReferences des offenen PRs enthält das Issue; der Issue-Text/Kommentare verlinken den PR; oder ein offener PR behebt offensichtlich dasselbe, was das Issue beschreibt. Ziel ist es, dass das Issue und der PR aufeinander verweisen – nur echte Lücken füllen und nicht-destruktive Schreibvorgänge bevorzugen:
- Kein Verweis in beide Richtungen → auf der Seite, die ihn vermisst, einen Hinweis-Kommentar posten (nicht-destruktiv). Eine Erwähnung von
#<PR>/#<N>erzeugt einen Querverweis, den GitHub in die Timeline des anderen spiegelt.gh issue comment <N> -R "$REPO" -b "Ein Fix ist in Arbeit in #<PR>." - Bereits in mindestens eine Richtung verlinkt → "bereits verlinkt – keine Aktion" aufzeichnen.
Nicht den PR-Text bearbeiten, es sei denn, der Benutzer möchte ausdrücklich, dass der PR das Issue beim Merge automatisch schließt. Ein Kommentar stellt einen Verweis her, löst aber kein automatisches Schließen aus – nur ein Schlüsselwort zum Schließen im PR-Text oder in einer Commit-Nachricht tut das. Wenn der Benutzer zustimmt, die Beschreibung niemals überschreiben: den Text unmittelbar vor dem Bearbeiten erneut abrufen und über stdin übergeben, damit nicht vertrauenswürdiger PR-Text nie eine shell-interpolierte Zeichenkette durchläuft:
body=$(gh pr view <PR> -R "$REPO" --json body --jq .body)
printf '%s\n\nSchließt #%s\n' "$body" "<N>" | gh pr edit <PR> -R "$REPO" --body-file -
Bereits vorhandene Verweise nicht duplizieren.
Eimer C – Ausstehend (keine Lösung, kein ausstehender PR). Nur lokal eine Priorität und eine Änderungsumfangsschätzung vergeben (nächster Abschnitt).
Phase 4: Ausstehende Issues bewerten (NUR LOKAL)
Priorität – Kritisch / Hoch / Mittel / Niedrig. Berücksichtigen Sie:
- Auswirkung / Schweregrad – Sicherheit, Datenverlust, Absturz oder Korrektheitsfehler sind höher als Verbesserungen; Docs/Kosmetik sind am niedrigsten. Vorhandene Labels (
security,bug,crash,regression) sind starke Signale. - Reichweite – wie viele Benutzer/Workflows sind betroffen.
- Signal – Reaktionen (👍), doppelte Meldungen, Alter mit anhaltender Aktivität.
- Dringlichkeit – blockiert einen Release, hat eine Deadline oder hat eine aktive Regression.
Änderungsumfang – der Aufwandsproxy, ausgedrückt als size/*-T-Shirt-Eimer basierend auf der geschätzten Gesamtanzahl geänderter Zeilen (Hinzufügungen + Löschungen, ignorierte generierte/vendierte Dateien), unter Verwendung der Kubernetes/Prow-ähnlichen Schwelle:
| Eimer | Geschätzte Änderungszeilen |
|---|---|
size/XS | ≤ 10 |
size/S | 11 – 50 |
size/M | 51 – 300 |
size/L | 301 – 1000 |
size/XL | 1001 – 3000 |
size/XXL | > 3000 (große EPICs – als Kandidat für Aufteilung markieren) |
Nehmen Sie die Schätzung anhand der inhärenten Komplexität des Issues vor (betrifft es viele Dateien? Erfordert es neue API-Endpunkte, Datenmigrationen, architektonische Änderungen?). Allein die Wörter des Issues reichen nicht – wenn nötig, die Codebasis konsultieren, um das Schadensrisiko zu verstehen, aber oft ist eine fundierte Schätzung aus dem Issue selbst möglich.
Ausgabeformat für ausstehende Issues (nur lokal):
#<N>: <Titel>
Priorität: <Kritisch|Hoch|Mittel|Niedrig>
Umfang: <size/XS|size/S|size/M|size/L|size/XL|size/XXL|
> (ungefähr <N> Gesamtzeilen)
Phase 5: Änderungen zur Genehmigung vorlegen
Nach den Phasen 1–4:
- Jede vorgeschlagene Aktion als Liste anzeigen (Details zur Übersichtlichkeit ein- und ausklappbar halten).
- Eine Bestätigung für Schreibvorgänge anfordern: Merges, Schließen von Issues, Kommentare. Niemals ohne ausdrückliche Genehmigung ausführen.
- Nach der Genehmigung die genehmigten Befehle in der Sequenz ausführen (zuerst Merges, damit die Issue-Phase die Ergebnisse sieht).
- Nach Abschluss eine Zusammenfassung anzeigen und zu den verbleibenden ausstehenden Issues mit ihren lokalen Bewertungen übergehen.
Sicherheitsregeln
- Nur genehmigte Schreibvorgänge. Jeder Merge, jeder Issue-Close, jeder Kommentar erfordert die explizite Zustimmung des Benutzers im aktuellen Kontext – nicht nur eine allgemeine Zuruf.
- Schreibgeschützte Überprüfung. Subagentenüberprüfungen werden lokal als Dateien gespeichert, nie auf GitHub gepostet (kein
gh pr review). - Lokale Bewertung. Priorität/Umfang sind nur im lokalen Arbeitsablauf sichtbar – sie werden nie als GitHub-Labels oder -Kommentare geschrieben.
- Keine endgültigen Entscheidungen. Jeder Merge wird zur menschlichen Bestätigung vorgelegt, nie autonom ausgeführt. Wenn ein Merge fehlschlägt oder nicht mehr bereit ist, ihn nicht erzwingen oder umgehen.
- Nicht maliziös. Nur agieren auf dem Repository, das der Benutzer angibt oder bestätigt. Remote-URLs vor der Verwendung validieren, um Befehlsinjektion oder die Anvisierung des falschen Hosts zu verhindern.
- Ehrlich sein. Wenn ein Zustand mehrdeutig oder unbekannt ist (z.B.
mergeable == "UNKNOWN",reviewDecision == null), nicht raten. Nicht bereit als nicht bereit melden.
Siehe auch
- Überprüfung von Pull Requests – Subagenten-Prompt, Rubrik, Ausgabeformat für die Überprüfung von PR-Diffs (Phase 2 – nie überprüfte PRs).
- Häufige Muster – Nachschlagewerk für wiederkehrende GitHub-Workflow-Muster, die während der Triage auftreten.