Das Symptom
git pull, das seit Jahren wortlos seinen Dienst tat, bricht ab. Die Meldung lautet sinngemäß, ein Fast-Forward sei nicht möglich, und endet mit aborting. Nichts wurde geholt, nichts zusammengeführt, der Arbeitsbaum ist unverändert. Besonders beliebt ist die Meldung nach einem Git-Update, in einem frischen Container oder auf einem neuen Rechner, auf dem die alte Konfiguration fehlt. Der Kollege nebenan bekommt sie nicht.
Die Reflexe reichen von git reset –hard über das Löschen und Neuklonen des Repositorys bis zum verzweifelten git push –force, der dann anderen Leuten die Arbeit wegnimmt.
Die „Layer 8“-Wahrheit
Git hat nichts kaputtgemacht; es hat eine Entscheidung verweigert. Die Dokumentation von git pull zählt vier Wege auf, den entfernten Zweig in den eigenen zu integrieren: –ff-only, –rebase, –no-rebase (ein Merge) und –squash. Zum ersten steht dort, dass git pull –ff-only nur Fast-Forward-Aktualisierungen vornimmt und „fails if your local branch has diverged from the remote branch.“ Der nächste Satz ist der entscheidende: „This is the default.“ Bei der Option selbst heißt es noch einmal: „This is the default when no method for reconciling divergent histories is provided (via the –rebase flags).“
Ein Fast-Forward ist nur möglich, wenn die entfernte Geschichte eine Fortsetzung der eigenen ist; dann wandert der Zweigzeiger einfach nach vorn, ohne neuen Commit. Hat man selbst Commits gemacht, die der Server nicht kennt, und hat der Server Commits, die man selbst nicht kennt, gibt es zwei Möglichkeiten, die Zweige zu vereinen: Merge oder Rebase. Welche davon, ist Geschmack, Teamkonvention und Frage, ob die eigenen Commits schon veröffentlicht sind. Git weiß das nicht und rät nicht. Deshalb der Abbruch.
Die Dokumentation nennt auch den Weg, die Frage ein für alle Mal zu beantworten: „You can also set the configuration options pull.rebase, pull.squash, or pull.ff with your preferred behaviour.“ Wer die Meldung auf einem Rechner nie gesehen hat, hat dort mit großer Wahrscheinlichkeit pull.rebase gesetzt, vielleicht vor Jahren, vielleicht aus einem Blogartikel abgetippt. Auf dem neuen Rechner fehlt die Zeile, und das strenge Standardverhalten kommt zum Vorschein.
Zur Wahl selbst gibt die Dokumentation eine klare Warnung mit: Rebase schreibt Geschichte um, und das bekommt veröffentlichten Commits nicht. Für Arbeit, die noch auf keinem Server liegt, ist Rebase die saubere Variante mit linearer Geschichte; für geteilte Zweige ist der Merge die ehrliche. Für pull.rebase sind die Werte true, merges, false und interactive dokumentiert; false bedeutet Merge. Die Entscheidung dauert eine Minute. Die Alternativen, Neuklonen oder Force-Push, kosten im besten Fall Zeit und im schlechtesten die Commits eines anderen. Die Meldung ist der Moment, in dem Git fragt. Man sollte antworten, nicht ausweichen.