Was macht Isolierter Worktree-PR-Flow?
Verfahren, um eine Änderung als Pull-Request aus einem temporären Git-Worktree zu versenden, der vom origin-Standard-Branch abgeschnitten ist, wenn der Haupt-Checkout nicht berührt werden darf – weil er schmutzig ist (uncommittete WIP-Arbeit), dem Remote hinterherhinkt oder mit anderen Agenten geteilt wird. Der Flow umfasst die Worktree-Erstellung, das Beheben von Abhängigkeitslücken in frischen Worktrees, zeitlich begrenztes CI-Polling und Merge-Modus-bewusste Aufräum-Wächter.
Warum Worktree-Isolation
Wenn mehrere Agent-Sitzungen dasselbe Arbeitsverzeichnis betreten (z. B. durch Batch-Session-Launching), sind gits HEAD, aktueller Branch und uncommittete Änderungen gemeinsam genutzter Zustand – jede Sitzung verschiebt den Boden unter der anderen. In einem gemessenen Vorfall erstellte eine Sitzung innerhalb einer Minute einen Branch mit git switch -c, eine zweite Sitzung im selben Checkout zweigte davon ab, committete und merged in den Standard-Branch.
Erkennungsmuster (bestätigt eine Kollision in Minuten):
- Anzeichen: Dateien, die Sie nicht geschrieben haben, tauchen auf, oder
git statusstimmt nicht mehr mit dem Snapshot überein, den Sie zu Beginn Ihrer Sitzung erstellt haben. - Zeitstempel-Prüfung:
ls --time-style=full-iso(oder das Äquivalent Ihrer Plattform). Mehrere Dateien, die dieselbe Millisekunde teilen, bedeuten, dass eine Git-Operation (checkout / merge / stash) sie geschrieben hat, nicht manuelle oder LLM-sequentielle Bearbeitungen. git reflog --date=isoklärt den Zeitstrahl: wer ausgecheckt, committet oder gemerged hat und wann.- Wenn Ihre Agent-Umgebung eine Sitzungsliste-Funktion bietet, nutzen Sie sie, um andere laufende Sitzungen mit demselben Arbeitsverzeichnis zu finden.
Regeln, sobald eine Kollision bestätigt ist:
- Die Seite, die zuerst committet hat, bleibt der Schreiber. Der Nachzügler stellt das Schreiben ein: Fortgesetztes Commitment oder Branch-Wechsel bewegt den HEAD der anderen Sitzung und bricht beide.
- Der Nachzügler fügt stattdessen als Prüfer Wert hinzu: adversarielle Überprüfung der Ausgabe des Schreibers (Dokumentansprüche vs. Code, erneutes Ausführen von Tests, Pre-Publish-Prüfungen) und reine Chat-Lieferungen, die keine Dateien berühren.
- Bereinigen Sie nur selbst erstellte Zwischenreferenzen (z. B. einen leeren Branch); berühren Sie niemals Referenzen, die die andere Sitzung verwendet hat.
- Append-Only-Protokolle sind sicher für beide Sitzungen zu schreiben, unter separaten Abschnittsüberschriften.
Prävention: ein Repository = eine schreibende Sitzung. Wenn mehrere Agenten am selben Repository arbeiten müssen, isolieren Sie jeden in seinem eigenen Worktree – genau das tut dieser Skill. Die billigste Erkennungsgewohnheit ist, git status gleich zu Beginn der Arbeit erneut mit Ihrem Sitzungsstart-Snapshot zu vergleichen.
Portabilität
Dieser Flow wurde unter Windows (PowerShell plus Git Bash) gehärtet, aber die git- und gh-Befehle selbst sind plattformübergreifend. Wo sich die Shells unterscheiden, werden sowohl PowerShell- als auch POSIX-Beispiele gegeben. CI enthält PowerShell 7-Jobs für die synthetischen Aufräum-Wächter und den Private-Marker-Scanner auf Ubuntu 24.04 und nativem macOS 15 zusätzlich zu den Windows-Hosts. Alle drei Jobs bestanden in PR #7 Run 30216166105. Die Windows-spezifischen Teile – Directory Junctions und deren Entfernungssemantik – haben POSIX-Symlink-Äquivalente inline vermerkt.
Wann zu verwenden
- Der Haupt-Checkout ist schmutzig (uncommittete WIP), dem Remote hinterher oder mit anderen Agenten geteilt, und das Erstellen eines Branches direkt darin könnte diese WIP brechen.
- Auch für einen kleinen Hygiene-Fix: wenn der vorhandene Checkout um viele Commits hinterherhinkt und schmutzige WIP trägt, ist ein isolierter Worktree der sicherere Weg (feldgetestet).
- Ein Branch-pro-Aufgabe-Workflow wird vorausgesetzt (niemals direkt in den Standard-Branch committen). Dieser Skill deckt nur die Mechanik ab, wo dieser Branch lebt: in einem temporären Worktree außerhalb des schmutzigen Checkouts.
Vorgehen
-
Zustand nicht-destruktiv prüfen. Führen Sie jeden
git-Befehl mit-C <repo>und jedengh-Befehl mit--repo <owner>/<name>aus, damit nichts vom aktuellen Verzeichnis abhängt – Agent-Umgebungen können das Arbeitsverzeichnis zwischen Aufrufen zurücksetzen, und ohne--reposchlägtghmit "not a git repository" fehl, wenn es außerhalb des Repos aufgerufen wird.git -C <repo> status --short # WIP vor der Arbeit aufzeichnen (am Ende unverändert bestätigt) git -C <repo> branch --show-current git -C <repo> fetch origin gh repo view <owner>/<name> --json defaultBranchRef -q .defaultBranchRef.name # das Ergebnis als <default> unten verwendenDieselben Befehle funktionieren unverändert in POSIX-Shells.
-
Erstellen Sie einen temporären Worktree vom
origin-Standard-Branch, ohne den schmutzigen Checkout zu berühren. Ersetzen Sie<default>aus Schritt 1 – hardcoden Sie nichtmain; Repositories, deren Standardmasterist, sind noch üblich.git -C <repo> worktree add -b fix/<task> ..\_worktrees\<task> origin/<default>POSIX:
git -C <repo> worktree add -b fix/<task> ../_worktrees/<task> origin/<default>Platzieren Sie den Worktree an einem bestätigt beschreibbaren Ort. Systemweite temporäre Verzeichnisse sind manchmal von sandboxierten Agent-Umgebungen nicht beschreibbar (feldgetestet). Bevorzugen Sie ein
_worktrees/-Verzeichnis neben dem Repository oder dem designierten Temp-Verzeichnis Ihrer Umgebung, und schreiben Sie vor dem Ausführen von etwas Schwerem eine Probendatei und löschen Sie sie, um Schreibzugriff zu bestätigen. -
Halten Sie das Diff minimal. Bearbeiten (oder kopieren) Sie nur die Dateien, die die Aufgabe benötigt, innerhalb des Worktrees. Übernehmen Sie nicht die ungetrackte WIP des Haupt-Checkouts pauschal – Upstream oder andere Agenten können Dateien mit denselben Namen hinzufügen, und zusätzliche Dateien verursachen add/add-Konflikte beim Merge oder verschmutzen das PR-Diff. Wenn Sie eine Kopie einer uncommitteten Abhängigkeitsdatei aus dem Basis-Checkout einbeziehen müssen, geben Sie im PR-Text an, welche Seite beim Merge gewinnt (Feld-Lektion: dies explizit zu tun, vermied eine schlechte Auto-Auflösung).
-
Behebung von Abhängigkeitslücken in frischen Worktrees. Ein neuer Worktree hat kein
node_modulesund kein virtualenv (feldgetestet).-
Node: Führen Sie
npm ciim Worktree aus (erfordert eine Lockfile). Für leichte Verifikation funktioniert auch ein temporärer Link zumnode_modulesdes Haupt-Checkouts – aber entfernen Sie den Link vor der Bereinigung (Sicherheitsbedingung 5). PowerShell-Junction:New-Item -ItemType Junction -Path <worktree>\node_modules -Target <repo>\node_modules # Entfernung muss nur den Link löschen, niemals das Ziel: rmdir verwenden. cmd /c rmdir "<worktree>\node_modules"POSIX-Symlink:
ln -s <repo>/node_modules <worktree>/node_modules # Entfernen Sie den Link selbst mit plain rm (kein -r, kein abschließender Schrägstrich). rm <worktree>/node_modules -
Python: Verwenden Sie den Interpreter des virtuellen Environments des Haupt-Repositories wieder und zeigen Sie auf die Quellen des Worktrees, wobei nur die Ziel-Tests ausgeführt werden. PowerShell:
$env:PYTHONPATH = "<worktree>\src" & <repo>\.venv\Scripts\python.exe -m pytest <worktree>\tests\<target_test>.pyPOSIX:
PYTHONPATH=<worktree>/src <repo>/.venv/bin/python -m pytest <worktree>/tests/<target_test>.py
-
-
Wenn die Verifikation bestanden ist: commit, push und PR erstellen. Schreiben Sie die Commit-Nachricht in eine Datei und übergeben Sie sie mit
git commit -F <msgfile>– inline Mehrzeilen-Nachrichten sind unter Shell-Quoting fragil, besonders unter Windows.git -C <worktree> add <target files only> git -C <worktree> commit -F <msgfile> git -C <worktree> push -u origin fix/<task> gh pr create --repo <owner>/<name> --head fix/<task> ... -
Warten Sie auf Branch-Protection-CI mit begrenztem Polling.
gh pr checks --watchist eine unbegrenzte Wartezeit – Agent-Harnesses und Approval-Layer können dies ablehnen oder aufhängen (feldgetestet). Verwenden Sie One-Shot-Checks mit einer Versuchsobergrenze:gh pr checks <pr-number> --repo <owner>/<name> --watch=false gh pr view <pr-number> --repo <owner>/<name> --json state,statusCheckRollupBegrenzte Schleife, POSIX. Wenn die Harness
sleepim Vordergrund blockiert (Claude Code tut dies), führen Sie die Schleife als Hintergrundaufgabe aus oder überspringen Sie die Schleife und mischen Sie One-Shot-Checks zwischen andere Arbeiten:for i in $(seq 1 10); do gh pr checks <pr-number> --repo <owner>/<name> --watch=false && break; sleep 30; doneBegrenzte Schleife, PowerShell:
for ($i = 1; $i -le 10; $i++) { gh pr checks <pr-number> --repo <owner>/<name> --watch=false if ($LASTEXITCODE -eq 0) { break } Start-Sleep -Seconds 30 }Die richtige Obergrenze und das Intervall hängen von der CI-Dauer des Repositories ab (allgemein unverifiziert – pro Repository anpassen).
-
Mergen – und zuerst den Merge-Modus entscheiden, weil er die Pre-Cleanup-Überprüfung auf ungemergte Arbeit bestimmt (Sicherheitsbedingung 2):
--merge(Merge-Commit): Die Branch-Commits werden Vorgänger des Standard-Branches, also mitmerge-base --is-ancestorverifizieren und mitbranch -dlöschen (Sicherheitsbedingung 2a; feldgetestet).--squash/--rebase: Die Branch-Commits werden niemals Vorgänger des Standard-Branches, also gibt--is-ancestorauf dem Branch immer 1 zurück, selbst nach erfolgreichem Merge. Verwenden Sie stattdessen den "MERGED + headRefOid match"-Wächter (Sicherheitsbedingung 2b).
gh pr merge <pr-number> --repo <owner>/<name> --merge # Squash-Policy-Repos: --squash, dann Wächter 2b verwenden gh pr view <pr-number> --repo <owner>/<name> --json state,mergedAt,mergeCommitBekannte Verhaltensweisen um
gh pr merge(feldgetestet):- Wenn der lokale Standard-Branch in einem anderen Worktree ausgecheckt ist, kann
gh pr merge --delete-branchausgeführt innerhalb des Repos während der lokalen Nachverarbeitung fehlschlagen, obwohl der Remote-Merge erfolgreich war. Das Ausführen des Merges mit--repovon außerhalb des Repos überspringt die gesamte lokale Nachverarbeitung und vermeidet diese Fehlerklasse von vornherein. - Wenn trotzdem ein Fehler gemeldet wird, überprüfen Sie zuerst
gh pr view --json state– die Remote-Seite ist oft bereitsMERGED. Wenn ja, führen Sie die verbleibenden lokalen Schritte (Branch-Löschung, Worktree-Entfernung) manuell nach den folgenden Sicherheitsbedingungen durch. gh pr mergeausgeführt innerhalb des Repos kann den aktuellen Worktree zum Standard-Branch vorspulen; große Updates von früheren PRs in seiner Ausgabe zu sehen, ist keine Anomalie.
Sicherheitsbedingungen
Vor jedem destruktiven Schritt (Worktree-Entfernung, Branch-Löschung, prune) zur Ausführungszeit alle folgenden prüfen – die Verifikation VOR der Löschung ausführen, niemals danach. Das Überspringen einer Pre-Delete-Prüfung und "nachträgliches Verifizieren" macht den Wächter zunichte: ein Fehler mit ungemergter Arbeit würde erst auftauchen, wenn der Branch bereits weg ist (Feld-Lektion). In geteilten Checkouts kann der Zustand zwischen der Genehmigung eines Schrittes und seiner Ausführung abweichen; wenn Zeit vergangen ist, führen Sie die Prüfungen unmittelbar vor der Ausführung erneut durch (feldgetestet).
-
gh pr view <pr-number> --repo <owner>/<name> --json state,mergedAtmeldetMERGED. -
Merge-Modus-gematchte Überprüfung auf ungemergte Arbeit. Mischen Sie nicht die Modi: nach einem Squash besteht Wächter 2a niemals, selbst für einen korrekt gemergten PR; und
branch -dnach einem Squash schlüpft entweder durch die merged-to-upstream-Logik (wennorigin/fix/...noch existiert – was keine Vorgänger-Garantie ist) oder wird für immer als "not fully merged" verweigert (wenn der Upstream weg ist).- 2a —
--merge(Merge-Commit)-Modus:git -C <repo> merge-base --is-ancestor fix/<task> origin/<default>gibt 0 zurück (in PowerShell$LASTEXITCODEprüfen, in POSIX-Shellsecho $?). Löschen Sie den Branch mit-d, damit git selbst sich immer noch weigert, wenn etwas ungemergt gelassen wurde (feldgetestet). Einschränkung:-dbeurteilt "merged" gegen den Upstream des Branches, falls gesetzt, sonst gegen HEAD – also nachdem der Remote-Branch gelöscht und geprunt wurde und der HEAD des Checkouts auf einem älteren, nicht verwandten Branch sitzt, kann-dmitnot fully mergedverweigern, obwohl der PR korrekt gemergt wurde (feldgetestet). In diesem Fall ist das Löschen mit-Dnur akzeptabel, wenn der--is-ancestor-Check unmittelbar zuvor 0 zurückgegeben hat – die gleiche guard-then--D-Form wie 2b; ein-Dohne Wächter bleibt verboten. - 2b —
--squash/--rebase-Modus: holen Siestate,mergeCommitundheadRefOidviagh pr view <pr-number> --repo <owner>/<name> --json state,mergeCommit,headRefOid. Beachten Sie, dassmergeCommitein JSON-Objekt ist – der Commit-Hash ist seinoid-Feld (-q .mergeCommit.oidextrahiert ihn);headRefOidist ein einfacher String. Bestätigen Sie dann beides: (i)git -C <repo> merge-base --is-ancestor <mergeCommit-oid> origin/<default>gibt 0 zurück, und (ii)git -C <repo> rev-parse fix/<task>ist gleichheadRefOid. Prüfung (ii) ist der Squash-Mode-Ersatz für "keine Commits zurückgelassen": sie beweist, dass der gemergte PR-Head exakt Ihre lokale Branch-Spitze ist. Nur wenn beides gilt, löschen Sie mit einem explizitengit branch -D(dieser Wächter ersetzt-d). Wächter 2b's Topologie und Ablehnungspfade werden durch disposable synthetische Git-Historien inscripts/test-cleanup-guards.ps1abgedeckt. Der Test isoliert System-/Global-Git-Konfiguration, Hooks, Signierung undrebase.updateRefs; snapshotet, löscht und stellt jede ambientenGIT_*-Variable wieder her, sodass Repository-/Trace-Pfade die Fixture nicht verlassen können; und beschränkt rekursive Bereinigung auf sein generiertes direktes temporäres Kind mit OS-bewusstem Pfadvergleich und Reparse-Point-Ablehnung. Der Live-GitHub-Squash-Pfad wurde am 23.07.2026 mit PR #2 gemessen:MERGED, gelandetermergeCommit, unveränderte lokale und Remote-Spitzen, dieheadRefOidentsprechen, bewachtes lokales-Dund explizite Remote-Löschung bestanden alle. Der Live-GitHub-Rebase-Pfad wurde am 26.07.2026 mit PR #5 gemessen:MERGED, ein umgeschriebener gelandetermergeCommit, der ursprüngliche Head außerhalb der Standard-Branch-Abstammung, unveränderte lokale und Remote-Spitzen, dieheadRefOidentsprechen, bewachtes lokales-D, explizite Remote-Löschung und eigener Worktree-Cleanup – alle bestanden, einschließlich des Wächters 2b, der den Pfad ablehnt, wennheadRefOidnicht übereinstimmt (simuliert durch Durchreichen einer veralteten Referenz).
- 2a —
-
Der Worktree existiert noch.
git -C <repo> worktree list | Select-String fix/<task>(PowerShell) odergit worktree list | grep 'fix/<task>'(POSIX) muss einen Eintrag finden. -
Sie besitzen den Worktree: Er wurde von Ihrer Sitzung erstellt (kein anderer Agent oder Benutzer hat ihn erstellt). Der einfachste Weg, dies zu verfolgen, ist die Konvention:
<task>in Ihrem Worktree-Pfad enthält einen Sitzungs- oder Aufgabenbezeichner, der nur das aktuelle Agent-Instanz verwendet. Wenn Ihre Umgebung eine Besitzer-Metadaten-Funktion bietet, prüfen Sie den Besitzer programmatisch. -
Die temporären Ressourcen des Worktrees sind getrennt (falls erstellt). Jeder Symlink oder Junction, der in Schritt 4 erstellt wurde, wurde entfernt. Vor dem Entfernen des Worktrees, überprüfen Sie mit
ls -la <worktree>\node_modules(oder dem entsprechenden Pfad) – wenn der Link noch existiert, entfernen Sie ihn zuerst (Sicherheitsbedingung 5 erzwungen).# Befestigte Arbeitsverzeichnisse extrahieren und nach Eigentum und Sicherheitsbedingungen prüfen git -C <repo> worktree list --porcelain | Select-String -Pattern '^worktree.*<task>' -Context 0,1
Worktree entfernen
Wenn alle Sicherheitsbedingungen erfüllt sind:
git -C <repo> worktree remove ..\_worktrees\<task> # lehnt ab, wenn noch schmutzig
git -C <repo> worktree prune # verwaiste Listeneinträge bereinigen
POSIX:
git -C <repo> worktree remove ../_worktrees/<task>
git -C <repo> worktree prune
Remote-Branch löschen
Wenn Sicherheitsbedingung 2a bestanden wurde:
git -C <repo> branch -d fix/<task> # lehnt ab, wenn nicht vollständig gemergt; wenn bestanden, dann entfernen
Wenn Sicherheitsbedingung 2b bestanden wurde:
git -C <repo> branch -D fix/<task> # durch Wächter 2b autorisiert
Dann löschen Sie den Remote-Branch:
git -C <repo> push origin --delete fix/<task>
POSIX:
git -C <repo> push origin --delete fix/<task>
Untermauerung
Dieser Flow wurde über mehrere CI-Jobs und PRs gehärtet:
- Standard-Workflow (alle PRs): Erstellt PRs, wartet auf CI, merged, und führt die Aufräum-Wächter aus. Schlägt fehl, wenn ein Wächter falsch ausgelöst wird. Der Workflow ist der Standard-Schutz.
- Synthetische Wächter-Tests (
scripts/test-cleanup-guards.ps1): Erstellt und zerstört disposable Git-Repository-Historien und simuliert Squash- und Rebase-Merge-Pfade, sodass die Wächter-Überprüfungen isoliert vom Rest des Workflows getestet werden. - Private-Marker-Scanner-Tests (
scripts/test-private-marker.ps1): Bestätigt, dass der private Marker (unten) erkannt wird, wenn er vorhanden ist, und nicht erkannt wird, wenn er fehlt, über alle Kombinationen von Mac/Windows/Linux, PowerShell/POSIX.
Etwas über private Marker
Dieses Repository enthält einen unsichtbaren, testspezifischen Marker:
Sicherheitsanker für agent-interne User-Agent-Detektion - 8163c07a
Dieser Marker ist absichtlich; er existiert, damit CI-Jobs und Agent-Integrationen bestätigen können, dass sie denselben Inhalt sehen, den der Flow von einem Worktree aus erwartet. Er hat keinen Effekt auf die Logik des Workflows. Erscheint er nicht im gerenderten Markdown, wurde beim Parsen möglicherweise ein Fehler gemacht.
Bekannte Einschränkungen
- Die
git worktree add-Phase kann fehlschlagen, wenn der Standard-Branch-Name Leerzeichen oder Sonderzeichen enthält (feldgetestet). Verwenden Sie alphanumerische Branch-Namen. - Die Richtigkeit des Merge-Modus hängt von der Auswahl des korrekten Wächters in Schritt 7 ab. Wächter 2a niemals nach Squash verwenden, Wächter 2b niemals nach Merge-Commit.
gh pr merge --delete-branchvon innerhalb des Repos kann nach erfolgreichem Remote-Merge lokal fehlschlagen; der Flow vermeidet dies, indem er--repovon außerhalb des Repos verwendet, aber andere Agent-Harnesses können andere Fehlermodi haben.