Gestapelte Branches
Ein Stack ist eine Kette von Branches, in der jeder auf dem darunter aufbaut:
main → api → ui. Drei kleine PRs zu reviewen schlägt es, einen riesigen zu
reviewen.

Gitcito zeichnet ihn als Route: oben ein Start-Branch, darunter eine Station pro Ebene. Der PR jeder Station zielt auf die Station darüber, und die erste landet auf dem Start-Branch. Eine Station zeigt ihre eigenen Commits, ob sie ein Restack braucht, und nach dem Einreichen ihre PR-Nummer.
Die Route bearbeiten
Nichts läuft, bis du auf Anwenden drückst. Einen Branch wählen, eine Station verschieben, sie von der Route nehmen — all das ändert eine Liste auf dem Bildschirm. Die echte Operation rebased Branches und checkt sie aus, und das sollte ein neugieriger Klick nicht tun. Wenn die Route stimmt, führt Route anwenden sie als einen widerrufbaren Schritt aus; Verwerfen setzt die Zeichnung auf das zurück, was das Repository tatsächlich sagt.
Die Route ist in Merge-Reihenfolge gezeichnet: der obere Branch wird in den darunter gemergt, bis hinunter zu dem, auf dem der Stapel landet.
| Bedienelement | Was es tut |
|---|---|
| Das Feld Start | Wo der Stapel landet. Ändere es, und die ganze Kette wird auf den neuen Branch verknüpft und abgespielt. |
| Das Feld einer Station | Tauscht, welcher Branch an dieser Stelle steht. Der Branch, der die Route verlässt, wird nur ausgehängt, nie gelöscht. |
| ↑ / ↓ | Verschiebt eine Station um einen Platz. |
| ✕ | Nimmt die Station aus der Route; ihre Nachbarn rücken zusammen. |
| Station hinzufügen | Wähle einen Branch, den du schon hast — er kommt oben dazu — oder tippe einen Namen, den es noch nicht gibt: er wird auf der Spitze der letzten Station angelegt und ausgecheckt. |
| Die Pfeil-Schaltfläche | Checkt diese Station aus. |
Jedes Feld ist ein Tippfeld mit Vorschlägen: tippen filtert, ↑/↓ und Enter wählen,
und was du tippst, zählt auch abseits der Liste — eine Remote-Referenz wie
origin/main taugt also als Start-Branch.
Unter der Haube sind all diese Änderungen dieselbe Operation: die ganze Route, auf einmal zurückgegeben. Deshalb ist eine Geste ein Widerruf (⌘Z) und keine Spur halb angewandter Verknüpfungen.
Was eine Routenänderung kostet
Alles, was die Reihenfolge ändert — ein Tausch, ein Zug, ein anderer Start — spielt die Kette neu ab: die eigenen Commits jeder Station werden auf ihre neue Basis rebased. Zwei Stationen, die dieselben Zeilen anfassen, tauschen nicht ohne einen Menschen, und dann passiert nichts: die ganze Änderung wird zurückgenommen — Spitzen, Parent-Links und der halbe Rebase — und Gitcito nennt die beiden Stationen, die sich beißen. Ein angestupstes Dropdown darf einen nicht mitten im Rebase zurücklassen.
Restack ist die andere Hälfte der Abmachung: ein Rebase, den du beim Namen verlangt hast, hält beim Konflikt an und übergibt die Konfliktansicht — was auch der Weg zu dem Umordnen ist, das Gitcito abgelehnt hat: dort auflösen, dann die Station verschieben.
Das Widerrufen spielt die vorherige Route nach. Es erweckt nicht die alten Commits, denn die neuen sind dieselbe Arbeit mit anderen Eltern.
Alle pushen
Alle pushen pusht jede Ebene mit --force-with-lease und hört dort auf — gh stack push, ohne etwas zu öffnen. Stapel als PRs einreichen macht denselben
Push und dann die PR-Arbeit; nimm Alle pushen, wenn die Branches auf dem
Remote liegen sollen, aber noch keine Review ansteht.
Den Stack als verkettete PRs einreichen
Einreichen fragt zuerst: wie viele Pull Requests geöffnet und wie viele neu
ausgerichtet werden, auf welchem Remote, und je eine Branch → Basis-Zeile —
Pull Requests zu öffnen ist öffentlich und mühsam rückgängig zu machen. Der
Navigationsabschnitt in jedem Text ist das, was die Kette auf GitHub sichtbar
macht — GitHub kennt keine Stapel.
Das Einreichen passiert auf einem eigenen Bildschirm: erst der Plan, dann der Fortschritt Schritt für Schritt, am Ende die Links zu jedem Pull Request und zum Stapel.

Stack als PRs einreichen erledigt mit einem Klick, wofür Stacking-Tools Geld verlangen:
- Pusht jede Ebene mit
--force-with-lease(frische Branches tolerieren es, restackte brauchen es). - Öffnet für jede Ebene ohne PR einen — jeder basiert auf seinem
Parent-Branch, nicht auf
main, sodass jedes Review nur die eigenen Commits zeigt. Titel und Beschreibung stammen aus den Commits der jeweiligen Ebene. - Zielt jeden bestehenden PR um, dessen Basis abgedriftet ist.
- Schreibt einen Stack-Navigationsabschnitt in jeden PR-Body, damit ein Reviewer auf jeder Ebene die ganze Kette sehen kann und wo dieser PR darin steht.
Die Aktion ist idempotent: Drücke sie nach jedem Restack, jeder neuen Ebene oder jedem gemergten PR und sie konvergiert — nichts wird dupliziert, angefasst wird nur, was abgedriftet ist.
Wenn der unterste PR gemergt ist, räumt derselbe Button hinterher: das Kind der gemergten Ebene wird auf den Trunk umgehängt, das Tracking der Ebene aufgehoben, ihr lokaler Branch gelöscht (sicher — der Trunk enthält ihn nachweislich), die Kette restackt und jeder verbleibende PR umgezielt. Von unten nach oben mergen, Einreichen drücken, wiederholen.
Auf GitHub wird daraus auch ein echter Stapel
Verkettete Basen versteht jeder Host, und auf GitLab, Bitbucket und Azure DevOps sind sie alles, was es gibt. GitHub kann mehr: seit der Vorschau auf stacked pull requests ist ein Stapel ein Objekt auf dem Server. Sobald die Pull Requests existieren, meldet Gitcito sie als Stapel an — von unten nach oben — und du bekommst die Stapelkarte in der PR-Oberfläche, einen serverseitigen Cascading Rebase und einen Merge auf dem obersten PR, der jede darunterliegende Ebene mitlandet.
Ist das Repository nicht in dieser Vorschau, oder kann das Token keine Stapel verwalten, wird der Aufruf kommentarlos übersprungen: die Kette und ihr Navigationsabschnitt tragen sich selbst, genau wie auf den anderen Hosts.
Restack
Wenn ein unterer Branch sich ändert — du hast Review-Kommentare auf api
abgearbeitet —, ist jeder Branch darüber jetzt auf der falschen Basis gebaut.
Restack rebast die gesamte Kette kaskadierend mit rebase --onto, sodass
das Umschreiben eines Parents keine Commits in seine Kinder dupliziert. Nach
einem Restack drücke erneut Einreichen: Es force-pusht die umgeschriebenen
Ebenen und die PRs aktualisieren sich an Ort und Stelle.
Grenzen
- Das Einreichen ist vorerst nur für GitHub möglich (das Erstellen funktioniert auf allen vier Hosts, aber Umzielen und Body-Updates brauchen die GitHub-API).
- Das Aufräumen nach dem Merge der untersten Ebene erkennt Merge- und Rebase-Merges über die Abstammung, und Squash-Merges, indem es GitHub fragt, ob der PR des Branches gelandet ist — mit einem GitHub-Token wird also jeder Merge-Stil aufgeräumt. Auf anderen Hosts, oder ohne Token, muss das Tracking einer squash-gemergten Ebene weiterhin von Hand aufgehoben werden. Fetche außerdem zuerst — die Abstammungsprüfung liest den Trunk im Stand deines letzten Fetch.
- Der Stack-Abschnitt in einem PR-Body wird zwischen versteckten Markern gepflegt — deine eigene Beschreibung darüber bleibt erhalten.
- Umordnen und ein Trunk-Wechsel schreiben Historie um, auf jeder berührten Ebene. Die Branches gehören dir, und ungepushte Ebenen kosten nichts — aber eine Ebene, die bereits in Review ist, bekommt beim nächsten Einreichen einen Force-Push.
- Eine Ebene bewegt sich immer nur um einen Platz. Zwei Tausche sind zwei Rebases, und auf halbem Weg stehenzubleiben ist ein lesbarer Zustand; ein Zug, der drei Plätze weiter landet, ist es nicht.
- Eine Station wird rebased, also ist der Branch, auf dem der Stapel landet,
nie zugleich eine Station — und ein geschützter Branch ebenso wenig (
mainundmaster, solange du die Liste nicht änderst). Beide werden abgelehnt, statt geteilte Historie still umzuschreiben. - Vor dem Öffnen fragt das Einreichen das Remote, welche Branches wirklich angekommen sind, und nennt die fehlenden. GitHub beantwortet einen fehlenden Head mit einem nackten „Validation Failed“, mit dem niemand etwas anfangen kann. Der Branch, auf dem der Stapel landet, wird ebenfalls geprüft: existiert er nur lokal, bietet das Einreichen an, ihn zu pushen und weiterzumachen.
Wo die Verknüpfungen liegen
Die Parent-Verknüpfungen werden in der git config gespeichert, sie reisen also mit dem Repository mit und überleben einen erneuten Clone. Nichts davon liegt in einem Dienst.
Siehe auch: Interaktives Rebase · Hosting & Pull Requests