Softwareentwicklung

Ein Repository, mehrere KI-Arbeiter: Wie verhindert man, dass sie sich gegenseitig Änderungen zerstören?

Zwei KI-Arbeiter lesen dieselbe Datei. Der erste ergänzt eine Fehlerbehandlung, der zweite baut auf Grundlage des ursprünglichen Inhalts eine neue Funktion ein. Schreibt der zweite anschließend seine vollständige Fassung zurück, kann die Fehlerbehandlung wieder verschwinden, bevor sie überhaupt in einem Commit gesichert wurde. Git muss dabei keinen Konflikt melden: Im gemeinsam benutzten Arbeitsverzeichnis hat zunächst nur ein gewöhnlicher Schreibvorgang den vorherigen Inhalt ersetzt.

Dieses allgemeine Beispiel beschreibt die unmittelbarste Gefahr paralleler Entwicklungsarbeit. Daneben können getrennt bearbeitete Änderungen beim Zusammenführen fachlich kollidieren oder dieselbe Testdatenbank verändern. Ein belastbarer Ablauf braucht deshalb getrennte Arbeitsstände, klar zugeordnete Aufgaben und eine kontrollierte Übernahme der Ergebnisse. Git Worktrees liefern dafür einen wichtigen Baustein; die Koordination darüber hinaus bleibt eine eigene Entwicklungsaufgabe.

Ein eigener Branch reicht im gemeinsamen Verzeichnis nicht

Ein Branch bezeichnet in Git eine Entwicklungslinie. Er erzeugt für sich genommen kein zusätzliches Arbeitsverzeichnis. Wenn zwei Prozesse im selben Verzeichnis arbeiten, sehen und verändern sie dieselben ausgecheckten Dateien. Auch der Index, in dem Änderungen für den nächsten Commit vorgemerkt werden, gehört zu diesem gemeinsamen Arbeitsstand. Ein Agent kann dadurch versehentlich Änderungen des anderen mit aufnehmen oder zurücksetzen.

Für parallele schreibende Aufgaben bietet sich deshalb jeweils ein eigener Worktree mit einem eigenen Branch an. Ein Worktree ist ein zusätzliches Arbeitsverzeichnis desselben Repositories mit eigenem ausgechecktem Stand und eigenem Index. Beide Aufgaben können von demselben festgehaltenen Commit starten und anschließend unabhängig Dateien bearbeiten. Ihre Ergebnisse werden später ausdrücklich zusammengeführt.

Dabei bleibt ein Worktree eine organisatorische und technische Trennung innerhalb von Git, keine vollständige Sicherheitsgrenze. Git-Objekte und bestimmte Verwaltungsdaten werden weiterhin gemeinsam genutzt. Ein Prozess mit passenden Dateirechten kann außerdem in das benachbarte Arbeitsverzeichnis wechseln. Soll ein Agent fremde Arbeitsstände tatsächlich nicht verändern können, müssen seine Schreibrechte oder seine Ausführungsumgebung entsprechend begrenzt werden.

Eine einfache Grundregel lautet daher: Pro aktivem Ausführungsversuch gibt es einen eindeutig zugeordneten Arbeitsbereich und genau einen schreibenden Verantwortlichen. Auch ein Test-Agent braucht einen eigenen Bereich, wenn er Tests ergänzt oder Code korrigiert. Für die Prüfung eines Ergebnisses sollte er einen festgehaltenen Stand erhalten, der sich während seiner Untersuchung nicht unbemerkt verändert.

Konflikte entstehen auch ohne gemeinsame Dateien

Getrennte Arbeitsverzeichnisse verhindern das direkte Überschreiben, lösen aber keine Widersprüche zwischen Aufgaben. Angenommen, ein Agent verändert eine Preisschnittstelle so, dass sie künftig Bruttobeträge zurückgibt. Ein anderer ergänzt einen Export, der die bisher gelieferten Nettobeträge erwartet und selbst Umsatzsteuer hinzurechnet. Beide können unterschiedliche Dateien bearbeiten, ihre jeweiligen Tests bestehen und gemeinsam falsche Preise erzeugen.

Vor dem parallelen Start braucht es deshalb eine Betrachtung der betroffenen Verträge: Welche Bedeutung haben Daten, welche Zusagen macht eine Schnittstelle, und welches Verhalten setzen andere Komponenten voraus? Eine Dateiliste hilft bei der Eingrenzung, bildet diese Abhängigkeiten aber nur teilweise ab. Besonders gemeinsame Datenmodelle, Berechtigungsregeln und zentrale Konfigurationen verbinden oft weit auseinanderliegende Dateien.

Für einen Arbeitsauftrag sind folgende Angaben hilfreich:

Angabe Zweck im parallelen Ablauf
Ausgangscommit und Anforderungsstand Beide machen nachvollziehbar, auf welcher Grundlage gearbeitet wurde.
Erwartetes Verhalten Es liefert einen gemeinsamen Maßstab für Umsetzung und Prüfung.
Zuständiger Bereich und Ausschlüsse Sie begrenzen eigenständige Änderungen und unerwünschte Nebenarbeiten.
Betroffene Schnittstellen und Ressourcen Sie machen mögliche Überschneidungen mit anderen Aufgaben sichtbar.
Abhängigkeiten Sie bestimmen, welche Vorarbeit bereits übernommen sein muss.
Ergebnisnachweis Er verbindet den fertigen Commit mit tatsächlich ausgeführten Prüfungen.

Im Preisbeispiel wäre die geänderte Bedeutung der Schnittstelle eine gemeinsame Voraussetzung. Eine Möglichkeit besteht darin, diese Änderung zuerst umzusetzen und zu prüfen. Der Export startet anschließend auf diesem Stand. Alternativ kann eine ausdrücklich vereinbarte Übergangsschnittstelle parallele Arbeit ermöglichen. Welche Variante passt, hängt davon ab, ob der zusätzliche Abstimmungsaufwand durch die Parallelisierung gerechtfertigt ist.

Entdeckt ein Agent während der Umsetzung eine bislang unbekannte Überschneidung, muss er sie an die Arbeitssteuerung zurückmelden. Der betroffene Teil wartet dann auf Klärung oder eine neue Zuordnung. Eine stillschweigende Ausweitung auf benachbarte Komponenten würde die ursprüngliche Aufgabenverteilung entwerten.

Die Testumgebung gehört zum Arbeitsbereich

Zwei Worktrees können weiterhin dieselbe Datenbank verwenden. Setzt ein Testlauf deren Inhalt zurück, während der andere gerade Ergebnisse prüft, entsteht ein Fehler außerhalb der Versionsverwaltung. Ähnliche Überschneidungen betreffen feste Netzwerkports, temporäre Verzeichnisse, Container-Namen und gemeinsam beschriebene Ausgabedateien.

Zum Arbeitsbereich gehört deshalb auch die Umgebung, in der gebaut und getestet wird. Wo möglich, erhält jeder Ausführungsversuch eine eigene Testdatenbank oder ein ausreichend getrenntes Schema, eigene temporäre Pfade und eindeutig zugeordnete Dienste. Die Konfiguration muss diese Trennung tatsächlich verwenden. Ein eindeutiger Worktree-Name hilft wenig, wenn beide Anwendungen weiterhin dieselbe Standardverbindung zur Datenbank laden.

Nicht jede Ressource lässt sich sinnvoll vervielfachen. Ein gemeinsam verwendetes Testgerät oder eine aufwendige Integrationsumgebung kann einen exklusiven Zugriff verlangen. Dann muss die Steuerung diesen Zugriff vergeben und die betreffende Prüfung gegebenenfalls nacheinander ausführen. Währenddessen können unabhängige Analyse- oder Implementierungsaufgaben weiterlaufen.

Zur Freigabe einer Ressource gehört auch das Ende ihrer Nutzung. Ein abgebrochener Agent kann einen gestarteten Testprozess hinterlassen, der weiterhin Daten verändert. Bevor die nächste Aufgabe übernimmt, muss deshalb feststehen, dass die vorherigen verändernden Prozesse beendet oder wirksam vom Zugriff ausgeschlossen sind.

Ein fehlendes Lebenszeichen bedeutet noch keinen Stillstand

Sobald Aufgaben automatisch vergeben werden, wird die Wiederaufnahme nach einer Unterbrechung zum Konfliktrisiko. Ein Agent meldet sich nicht mehr, die Steuerung startet einen Ersatz, und kurz darauf arbeitet der ursprüngliche Prozess weiter. Ohne zusätzliche Absicherung bearbeiten nun zwei Ausführungen denselben Auftrag.

Ein Heartbeat, also ein regelmäßiges Lebenszeichen, hilft bei der Beobachtung. Sein Ausbleiben beweist jedoch nicht, dass der Prozess beendet wurde. Auch eine Lease, eine zeitlich begrenzte Zuweisung einer Aufgabe oder Ressource, stoppt nach ihrem Ablauf keinen bereits laufenden Schreibzugriff. Sie regelt zunächst, wem die Steuerung die Arbeit aktuell zurechnet.

Für eine robuste Neuvergabe braucht jeder Versuch eine eigene Kennung. Ergebnisse und Zustandsänderungen werden nur angenommen, wenn sie zur aktuell gültigen Zuweisung gehören. Prüfung und Übernahme müssen dabei atomar erfolgen, also ohne eine Lücke, in der zwischenzeitlich eine andere Ausführung zuständig werden kann. Ein verspätetes „erledigt“ des alten Agenten darf den neueren Aufgabenstand nicht überschreiben.

Bei gemeinsam veränderten Ressourcen lässt sich dieses Prinzip durch eine steigende Zuweisungsnummer durchsetzen, häufig als Fencing-Token bezeichnet. Die Stelle, die den Schreibvorgang tatsächlich ausführt, weist veraltete Nummern zurück. Unterstützt die Ressource eine solche Prüfung nicht, muss der alte Zugriff auf andere Weise zuverlässig unterbunden werden, bevor ein neuer beginnt. Ein Eintrag „Lease abgelaufen“ in einer Aufgabenliste genügt dafür nicht.

Für die Repositoryarbeit erleichtert ein eigener Worktree pro Versuch diese Trennung. Die alte Ausführung kann dann höchstens ihren alten Arbeitsstand weiter verändern; die Integrationsstelle nimmt ihr Ergebnis ohne gültige Zuordnung nicht mehr an. Voraussetzung bleibt, dass sie keinen direkten Schreibzugriff auf den Zielbranch oder fremde Arbeitsbereiche besitzt.

Die Zusammenführung braucht einen einzigen kontrollierten Weg

Am Ende liefern mehrere Aufgaben jeweils einen Änderungsvorschlag. Der gemeinsame Zielbranch sollte ausschließlich über einen geregelten Integrationsweg aktualisiert werden. Das kann eine manuell betreute Übernahme sein oder eine Merge-Warteschlange, die Kandidaten in definierter Reihenfolge vorbereitet und prüft. Parallele Implementierung bleibt damit möglich, während die Übernahme kontrolliert erfolgt.

Entscheidend ist der geprüfte Gesamtstand. Wenn zwei Aufgaben vom selben Ausgangscommit starten und die erste bereits übernommen wurde, muss die zweite mit diesem neuen Zielstand zusammengeführt werden. Geprüft wird anschließend die Kombination. Die früheren Tests des zweiten Aufgabenbranches belegen nicht automatisch, dass er mit der inzwischen integrierten Änderung zusammenarbeitet.

Auch zwischen Prüfung und Übernahme darf der Bezug nicht verloren gehen. Bewegt sich der Zielbranch währenddessen weiter, muss die Integration erkennen, dass ihre Grundlage überholt ist. Sie darf dann kein Ergebnis auf Basis des alten Stands ungeprüft übernehmen. Eine geeignete Merge-Warteschlange organisiert diese Reihenfolge und erneuert erforderliche Prüfungen.

Ein textuell konfliktfreier Merge ist dabei nur ein technischer Zwischenschritt. Im Preisbeispiel braucht der zusammengeführte Stand eine Prüfung, ob der Export die vereinbarte Betragsart korrekt verarbeitet. Gerade hier zeigt sich, weshalb grüne Tests allein kein ausreichender Qualitätsnachweis sind: Ihre Erwartungen müssen die gemeinsame Fachregel abbilden und dürfen nicht lediglich die getrennten Annahmen der Agenten bestätigen.

Bei einem echten Merge-Konflikt sollte dessen Bearbeitung als eigener nachvollziehbarer Schritt erfolgen. Eine pauschale Auswahl einer Dateiseite kann gültige Änderungen entfernen. Nach der Auflösung werden der entstandene Diff und das betroffene Verhalten erneut geprüft; die Konfliktlösung ist selbst eine Änderung, deren Folgen verstanden werden müssen.

Nach einer Kollision zuerst den vorhandenen Stand sichern

Wenn Änderungen bereits verschwunden oder vermischt sind, sollte zunächst keine weitere schreibende Arbeit auf dem betroffenen Bereich beginnen. Die laufenden Prozesse müssen kontrolliert beendet oder vom Zugriff getrennt werden. Anschließend wird der vorhandene Zustand gesichert, einschließlich unversionierter Dateien und noch nicht committeter Änderungen, bevor Bereinigungsbefehle zum Einsatz kommen.

Danach lässt sich anhand von Branches, Commits und Aufgabenprotokollen rekonstruieren, welche Ergebnisse entstanden sind. Das Git-Reflog kann helfen, frühere Positionen von Referenzen wiederzufinden, etwa nach einem versehentlichen Zurücksetzen. Nie committete und bereits überschriebene Dateiinhalte stellt es dagegen nicht verlässlich wieder her. Dafür kommen gegebenenfalls Editorhistorien oder separate Sicherungen infrage.

Die Wiederherstellung sollte auf einem bekannten Ausgangsstand erfolgen, auf den die gewünschten Änderungen gezielt übernommen werden. Erst danach folgt die erneute Prüfung des kombinierten Verhaltens. Bleibt ein Teil der früheren Arbeit unauffindbar, muss diese Lücke sichtbar bleiben, statt aus einer plausiblen Rekonstruktion einen vermeintlich nachgewiesenen Stand zu machen.

Was eine Orchestrierung dafür nachweisen müsste

Für Agenda als Aufgaben- und Orchestrierungsebene ergibt sich daraus ein konkretes Zielbild. Zu einer Aufgabe müssten die gültige Anforderungsfassung, der Ausführungsversuch, sein Arbeitsbereich und die beanspruchten Ressourcen auffindbar sein. Ein Status wie „zur Integration bereit“ müsste auf einen bestimmten Commit mit zugeordneten Prüfergebnissen zeigen. Damit ist eine Anforderung an den geplanten Ablauf beschrieben, kein bereits nachgewiesener Gesamtbetrieb.

Ein begrenzter Versuch sollte deshalb bewusst mehr als den erfolgreichen Normalfall untersuchen. Ein alter Agent liefert nach einer Neuvergabe verspätet sein Ergebnis; zwei Aufgaben benötigen dieselbe Testressource; der Zielbranch verändert sich während einer Integrationsprüfung. In jedem Fall muss nachvollziehbar bleiben, welcher Versuch noch handeln darf und welcher Stand tatsächlich geprüft wurde. Fachliche Grundsatzentscheidungen und produktive Freigaben können dabei weiterhin bewusst beim Menschen bleiben.

Für den Einstieg braucht es keine große Agentenorganisation. Zwei klar abgegrenzte Aufgaben in getrennten Worktrees, getrennte Testressourcen und eine kontrollierte Übernahme reichen, um die wesentlichen Grenzen zu untersuchen. Mehr Parallelität lohnt sich erst, wenn die Zusammenführung nicht regelmäßig neue Rekonstruktionsarbeit erzeugt. Der praktische Maßstab ist, ob du nach einer Unterbrechung erkennen kannst, welche Änderungen erhalten sind, welche zusammenpassen und weshalb genau dieser gemeinsame Stand übernommen werden darf.